> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Resolve Transfer Reconciliation

> Use this endpoint to resolve by hand one transfer that reconciliation parked in manual review. Each action serves exactly one transfer type.

On an outbound TED whose hold is preserved:

- `SETTLE` commits the hold and completes the transfer.
- `REVERT` cancels the hold and fails the transfer.

On an inbound credit whose STR0010R2 chargeback refund the automatic path could not finish:

- `RE_POST` pays the refund again. Before it pays anything, it asks the ledger what became of the compensation already on file. Only a compensation that moved nothing licenses a posting. One that already moved the gross closes the row where it stands, with nothing posted. One that moved any other amount is refused for good. Even the licensed case first searches the ledger for this chargeback's own refunds and adopts a live one already paying the gross instead of filing a second, so a refund that was paid can never be paid twice. A compensation on file that the ledger prices as live enters that same search as one of its members, so while a second live refund stands beside it, the row is not closed on it and no difference is quoted against it.
- `SETTLED_BY_HAND` posts nothing and records that the refund was arranged outside this platform, so it requires an `evidenceReference` that names the outside movement. Because this record also takes the row off the pending list, it is filed only over a ledger reading that completed and priced every posting it saw. A scan that the ledger truncated, a scan that it could not answer, and a scan holding a posting in a status this service cannot price are each refused as not confirmed instead of closed. Send the same request again under a new `X-Idempotency` key.

When the ledger holds more than one live refund for a chargeback, this platform debited the beneficiary more than once, and no action here takes a posting back: `RE_POST` is refused, and `SETTLED_BY_HAND` closes the row with every one of those transactions named on the closing record.

On every action except `RE_POST`, the ledger moves first, and the row is written only once the ledger reaches the state that the resolution claims, so a failure midway leaves the transfer exactly as it was found. `RE_POST` runs in the other order, because it is the one action that pays: the new compensation is stamped on the transfer the moment the ledger returns its ID, before anything judges what it paid. Every later failure leaves the row parked and naming the money, and repeating the identical request under a new `X-Idempotency` key (the key that earned the failure is fenced) converges on that stamp instead of paying a second time. A stamped compensation that the ledger cannot find is undecided, not absent, and is refused: wait, repeat the identical request under a new `X-Idempotency` key, and close the row with `SETTLED_BY_HAND` if it never clears. A refund that the ledger prices at anything other than the gross is a verdict that no retry changes, whether it is the compensation on file, one that the ledger scan found, or the one that this request filed: the row stays parked, the remaining difference is settled outside this platform, and the row is closed with `SETTLED_BY_HAND`.

The operator `reason` is required on every action. It is recorded in the audit trail with the subject resolved from the bearer token. This endpoint requires the `transfers:resolve` permission and a user token.



## OpenAPI

````yaml /en/openapi/v3-current/ted.yaml post /v1/transfers/{transferId}/reconciliation/resolve
openapi: 3.0.3
info:
  title: Bank Transfer (TED) Plugin API
  description: >-
    Complete API for Brazilian bank transfers (TED OUT, TED IN, P2P) through the
    Lerian platform, including transfer initiation, processing, status tracking,
    and cancellation.
  version: 1.1.9
servers:
  - url: https://ted.sandbox.lerian.net
    description: Sandbox (placeholder — not yet available for public access)
security:
  - BearerAuth: []
  - OAuth2ClientCredentials:
      - api
  - OAuth2Password:
      - api
tags:
  - name: Transfers API
    description: Endpoints for initiating, processing, tracking, and cancelling transfers.
  - name: Webhooks
    description: >-
      Endpoints for registering and managing tenant-scoped webhook subscriptions
      for transfer events.
  - name: Webhook DLQ
    description: Endpoints for inspecting and retrying webhook dead-letter queue messages.
paths:
  /v1/transfers/{transferId}/reconciliation/resolve:
    post:
      tags:
        - Transfers API
      summary: Resolve Transfer Reconciliation
      description: >-
        Use this endpoint to resolve by hand one transfer that reconciliation
        parked in manual review. Each action serves exactly one transfer type.


        On an outbound TED whose hold is preserved:


        - `SETTLE` commits the hold and completes the transfer.

        - `REVERT` cancels the hold and fails the transfer.


        On an inbound credit whose STR0010R2 chargeback refund the automatic
        path could not finish:


        - `RE_POST` pays the refund again. Before it pays anything, it asks the
        ledger what became of the compensation already on file. Only a
        compensation that moved nothing licenses a posting. One that already
        moved the gross closes the row where it stands, with nothing posted. One
        that moved any other amount is refused for good. Even the licensed case
        first searches the ledger for this chargeback's own refunds and adopts a
        live one already paying the gross instead of filing a second, so a
        refund that was paid can never be paid twice. A compensation on file
        that the ledger prices as live enters that same search as one of its
        members, so while a second live refund stands beside it, the row is not
        closed on it and no difference is quoted against it.

        - `SETTLED_BY_HAND` posts nothing and records that the refund was
        arranged outside this platform, so it requires an `evidenceReference`
        that names the outside movement. Because this record also takes the row
        off the pending list, it is filed only over a ledger reading that
        completed and priced every posting it saw. A scan that the ledger
        truncated, a scan that it could not answer, and a scan holding a posting
        in a status this service cannot price are each refused as not confirmed
        instead of closed. Send the same request again under a new
        `X-Idempotency` key.


        When the ledger holds more than one live refund for a chargeback, this
        platform debited the beneficiary more than once, and no action here
        takes a posting back: `RE_POST` is refused, and `SETTLED_BY_HAND` closes
        the row with every one of those transactions named on the closing
        record.


        On every action except `RE_POST`, the ledger moves first, and the row is
        written only once the ledger reaches the state that the resolution
        claims, so a failure midway leaves the transfer exactly as it was found.
        `RE_POST` runs in the other order, because it is the one action that
        pays: the new compensation is stamped on the transfer the moment the
        ledger returns its ID, before anything judges what it paid. Every later
        failure leaves the row parked and naming the money, and repeating the
        identical request under a new `X-Idempotency` key (the key that earned
        the failure is fenced) converges on that stamp instead of paying a
        second time. A stamped compensation that the ledger cannot find is
        undecided, not absent, and is refused: wait, repeat the identical
        request under a new `X-Idempotency` key, and close the row with
        `SETTLED_BY_HAND` if it never clears. A refund that the ledger prices at
        anything other than the gross is a verdict that no retry changes,
        whether it is the compensation on file, one that the ledger scan found,
        or the one that this request filed: the row stays parked, the remaining
        difference is settled outside this platform, and the row is closed with
        `SETTLED_BY_HAND`.


        The operator `reason` is required on every action. It is recorded in the
        audit trail with the subject resolved from the bearer token. This
        endpoint requires the `transfers:resolve` permission and a user token.
      operationId: resolveTransferReconciliation
      parameters:
        - $ref: '#/components/parameters/XOrganizationId'
        - $ref: '#/components/parameters/XIdempotencyKey'
        - name: transferId
          in: path
          required: true
          description: The unique identifier of the transfer.
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        description: >-
          Operator decision, justification, and evidence reference (required for
          `SETTLED_BY_HAND`).
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ResolveTransferReconciliationRequest'
      responses:
        '200':
          description: >-
            Indicates that the transfer was resolved. A ledger reference that
            names nothing is omitted instead of sent as the all-zeroes UUID:
            `compensationTransactionId` and `previousCompensationTransactionId`
            belong to the inbound actions, and `midazTransactionId` is absent on
            an inbound close of a row whose credit transaction was never proven.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResolveTransferReconciliationResponse'
        '400':
          description: >-
            BTF-0001: invalid `transferId`, missing idempotency key, an `action`
            other than `SETTLE`, `REVERT`, `RE_POST`, or `SETTLED_BY_HAND`, a
            `reason` outside 10 to 500 characters, an `evidenceReference` longer
            than 200 characters, or a `SETTLED_BY_HAND` that carries no
            `evidenceReference`.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDocument'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: >-
            BTF-0405: the caller lacks the `transfers:resolve` permission.
            BTF-0406: the bearer token is not a person (a service account or a
            token of another type), so this by-hand write cannot be attributed
            to an operator. No grant fixes this; call the endpoint with a user
            token. A user token whose owner or subject is only whitespace is
            refused with 401 BTF-0401 before this check.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDocument'
        '404':
          description: >-
            BTF-0200: transfer not found. BTF-0404: `X-Organization-Id` names an
            organization that this tenant does not operate.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDocument'
        '409':
          description: >-
            BTF-0110: the transfer is not a row that this action resolves, and
            nothing was resolved. `SETTLE` and `REVERT` need an outbound TED
            parked in manual review with a preserved hold. `RE_POST` and
            `SETTLED_BY_HAND` need an inbound credit parked in manual review,
            and `RE_POST` also needs a compensation already on file. BTF-0110
            also answers an inbound row whose compensation on file is no longer
            the one that the request was made against. The body then carries
            `compensationTransactionIdOnFile` and
            `expectedCompensationTransactionId` as bare transaction UUIDs.
            Either one is omitted when that column is empty, which is the
            ordinary state of a chargeback that the automatic path still owes a
            refund. Read the transfer again and resolve it against the
            compensation it now carries.


            BTF-0111: the ledger contradicts the requested resolution. The body
            carries `ledgerStatus`, omitted only when the ledger returned the
            transaction without one. Issue the other action. Only outbound
            transfers get this answer, because the other action on an inbound
            row closes the transfer.


            BTF-0115: the ledger holds a live posting for this chargeback on
            which this service cannot complete the chargeback: it moved an
            amount other than the gross, or its entries refund none of it. No
            retry changes either condition, because the amount and the entries
            of a transaction are the same on every later read. The posting can
            be the compensation already on file, a posting that the pre-post
            ledger scan found and that the transfer does not name, or the refund
            that this request just filed and stamped. The remedy is the whole of
            it: read that transaction in the ledger, settle whatever remains
            outside this platform, and close the transfer with
            `SETTLED_BY_HAND`. The body carries `transactionId`, the posting to
            open (which, when the ledger scan found it, is not the one that the
            transfer names), and `ledgerStatus`, omitted only when the ledger
            returned the transaction without one. The body carries no amount
            under any key, because no one measured a number beside a live
            posting.


            BTF-0116: a hand `RE_POST` filed its refund and the ledger cancelled
            it, so it paid nothing. This is not a shortfall: the cancelled
            refund is filed on the transfer and paid nothing, so there is
            nothing to settle outside this platform. Issue `RE_POST` again to
            file a new refund. The body carries `transactionId`, `paidAmount`
            (zero), `grossAmount`, and `ledgerStatus`.


            BTF-0117: the ledger holds more than one live refund for this one
            chargeback, so this platform debited the beneficiary more than once.
            Nothing was posted, and the transfer was not closed. Only `RE_POST`
            gets this answer, because `SETTLED_BY_HAND` records the same
            transactions on the closing record and closes the row. No action of
            this endpoint takes a refund back: read every transaction named here
            and return the surplus to the beneficiary outside this platform.
            Another `RE_POST` would file a third debit. Once the surplus is
            returned, `SETTLED_BY_HAND` records every transaction named here on
            the closing record and closes the transfer. The body carries
            `transactionIds`, every live refund for this chargeback that the
            ledger walk reached, as bare transaction UUIDs, and
            `liveRefundSetComplete`, which says whether those are all of them.
            The set is incomplete on any of four exits: a page that the ledger
            refused, a page answered with nothing, a refused direct read of a
            live candidate, and the page budget. On every exit except the
            refused direct read, the walk stops where it broke and does not
            resume, so a pair proven at that break is still this refusal while
            the ledger can hold a further live refund that nothing named. The
            detail says the same in words.


            BTF-0016: a request under this `X-Idempotency` key still holds the
            in-flight lease, because it is still running or because it already
            ended 5xx and recorded no outcome. `Retry-After` carries a poll
            interval, not the lease. While the first request is still running,
            resend the identical request after that interval; the answer replays
            from the first request as soon as it finishes. If an earlier request
            under this key answered 5xx without `X-Idempotency-Fenced: true`, no
            answer will ever be served from it: stop resending, read the
            resource this route acts on, and send the work under a new
            `X-Idempotency` key only if it did not land. The detail also names
            the 15-minute bound after which the lease lapses and a resend runs
            the work a second time; a poll still unanswered by then ends the
            same way.


            BTF-0018: the request under this `X-Idempotency` key already
            completed, and its response was too large to store for replay. Read
            the resource. Do not resend under a new key, because that runs the
            work a second time. This answer carries no `Retry-After`, because no
            wait produces the missing receipt.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDocument'
        '422':
          $ref: '#/components/responses/IdempotencyKeyRefused'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
        '500':
          description: >-
            BTF-9000: internal server error. BTF-9006: unexpected empty response
            from the service layer.


            BTF-9014: the ledger moved and the transfer could not be brought to
            rest: an outbound hold that finalized and left the row unwritten, a
            refund that a hand `RE_POST` filed, which the transfer already names
            and whose closing was refused, or a refund that may have been filed
            and that the transfer does not name. Read the transfer, then send
            the identical request again under a new `X-Idempotency` key to
            converge the row with the ledger. The same key is refused with 422
            BTF-0014 (`refusalCode: IDEMPOTENCY_OUTCOME_UNRECORDED`) for the
            retention window when this answer carried `X-Idempotency-Fenced:
            true`, and with 409 BTF-0016 while the in-flight lease holds when it
            carried `false`. The repeat converges on the ledger state of this
            transfer, not on the key, so it cannot move money twice. If the
            repeat does not clear the error, the ledger and the transfer row
            still disagree, and the transfer needs manual inspection.
          headers:
            X-Idempotency-Fenced:
              $ref: '#/components/headers/XIdempotencyFenced'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDocument'
        '502':
          description: >-
            BTF-2000: the ledger could not confirm the resolution. The transfer
            was not changed, and the identical request can be sent again under a
            new `X-Idempotency` key. The key that earned this 502 is refused
            with 422 BTF-0014 (`refusalCode: IDEMPOTENCY_OUTCOME_UNRECORDED`)
            for the retention window when this answer carried
            `X-Idempotency-Fenced: true`, and with 409 BTF-0016 while the
            in-flight lease holds when it carried `false`.


            On a `RE_POST`, nothing was posted and nothing was stamped. BTF-2000
            also covers a compensation that the ledger has not decided yet: one
            that it still holds live, and one that it cannot find at all, which
            is read as undecided instead of absent, so that a stamp written
            against the wrong ledger can never license a second real debit. It
            also answers both inbound actions when the count of live refunds for
            this chargeback did not finish: a result set that the page walk
            could not reach the end of, a ledger that could not be asked, or a
            refund in a status that this service cannot price, which the detail
            names. Neither closing the row nor quoting a difference is done over
            a count that was never established. Repeat the identical request
            under a new key. A `SETTLED_BY_HAND` that never clears is a row to
            inspect, not one to close blind.
          headers:
            X-Idempotency-Fenced:
              $ref: '#/components/headers/XIdempotencyFenced'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDocument'
        '503':
          description: >-
            BTF-9005: a required service dependency is not configured. BTF-9007:
            the transfer repository timed out. BTF-9008: the transfer repository
            is unavailable.


            On an inbound closing, BTF-9008 also covers a failure to enqueue the
            chargeback announcement that the closing owes the client. The
            announcement rides inside the closing transaction, so nothing was
            written, no money moved, and the same request can be repeated under
            a new `X-Idempotency` key. BTF-9008 also answers an inbound
            `RE_POST` or `SETTLED_BY_HAND` whose chargeback refund the ledger
            already held and whose row the storage would not point at it. No
            hand action moved anything, nothing was posted, the transfer is
            exactly where it was found, and the same request can be sent again
            under a new `X-Idempotency` key, which reads the ledger again, finds
            that refund, and stamps it.


            BTF-9016: this tenant's database cannot record the resolution's
            history row. Nothing was written and no ledger call was made. Apply
            the pending migrations to this tenant and send the identical request
            again under a new `X-Idempotency` key.


            BTF-9000: the idempotency store was unavailable before the handler
            ran, so nothing ran. Send the same request again under the same
            `X-Idempotency` key.


            BTF-0019: the work under this `X-Idempotency` key ran, and neither
            its response nor its outcome fence could be stored, so the key
            protects nothing and a resend can run the operation a second time.
            Read the resource before you send anything else.


            BTF-0020: the work under this `X-Idempotency` key ran and its
            response could not be stored for replay, but the key is still held.
            This answer is not the outcome of that work. Read the resource, and
            resend under a new key only if the work did not land.


            BTF-9017: the tenant organization list is absent or unreadable.
            Retry with the same idempotency key once it is configured.
          headers:
            X-Idempotency-Fenced:
              $ref: '#/components/headers/XIdempotencyFenced'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ProblemDocument'
components:
  parameters:
    XOrganizationId:
      name: X-Organization-Id
      in: header
      required: true
      description: >-
        Midaz organization scope for the request, used for downstream CRM, Fees,
        and Midaz calls. Required on org-scoped transfer routes in every
        deployment mode; a missing or non-UUID value returns 400. This is not
        the tenant identifier — tenantId is derived from the bearer JWT or
        authenticated context, never from this header. Background workers (TED
        IN poller, reconciliation) have no request header and, in single-tenant
        mode, fall back to the deployment's `ORGANIZATION_ID` env.
      schema:
        type: string
        format: uuid
      example: 019c96a0-0a98-7287-9a31-786e0809c769
    XIdempotencyKey:
      name: X-Idempotency
      in: header
      required: true
      description: >-
        Required idempotency key for safe retries. Use a UUID v4 or unique
        business identifier. If the same key is sent again and the original
        request was already processed, the cached response is returned.


        See [Retries and idempotency](/en/reference/retries-idempotency) for
        details.
      schema:
        type: string
        maxLength: 255
      example: 019c96a0-aa10-7abc-d1e2-8c9d0e1f2a3b
  schemas:
    ResolveTransferReconciliationRequest:
      type: object
      required:
        - action
        - reason
      properties:
        action:
          type: string
          enum:
            - SETTLE
            - REVERT
            - RE_POST
            - SETTLED_BY_HAND
          example: SETTLE
        reason:
          type: string
          minLength: 10
          maxLength: 500
          example: JD cabine ticket 4471 confirms settlement at 10:42
        evidenceReference:
          type: string
          maxLength: 200
          description: Required for `SETTLED_BY_HAND`.
          example: STR0008 ctrl 202609061042
    ResolveTransferReconciliationResponse:
      type: object
      properties:
        transferId:
          type: string
          format: uuid
          example: 770e8400-e29b-41d4-a716-446655440003
        status:
          type: string
          example: COMPLETED
        reconciliationStatus:
          type: string
          example: RESOLVED
        resolvedAt:
          type: string
          format: date-time
          example: '2026-09-06T12:00:00Z'
        midazTransactionId:
          type: string
          format: uuid
          example: 11111111-2222-3333-4444-555555555555
        compensationTransactionId:
          type: string
          format: uuid
          example: 66666666-7777-4888-9999-aaaaaaaaaaaa
        previousCompensationTransactionId:
          type: string
          format: uuid
          example: 33333333-4444-4555-8666-777777777777
    ProblemDocument:
      type: object
      description: >-
        The RFC 9457 problem document that the service answers every error with,
        on `application/problem+json`. Route-specific members (for example
        `refusalCode`, `transactionId`, `ledgerStatus`, `systemplaneKey`) appear
        flat at the top level beside these.
      additionalProperties: true
      required:
        - type
        - title
        - status
        - detail
        - code
        - requestId
        - service
        - category
      properties:
        type:
          type: string
          description: >-
            A URI that names the error code:
            `https://errors.lerian.studio/v1/<code>`.
          example: https://errors.lerian.studio/v1/BTF-0200
        title:
          type: string
          description: The HTTP status text.
          example: Not Found
        status:
          type: integer
          description: The HTTP status code.
          example: 404
        detail:
          type: string
          description: A human-readable explanation of this occurrence.
          example: transfer not found
        instance:
          type: string
          description: The trace ID of this request, when one was recorded.
          example: 4bf92f3577b34da6a3ce929d0e0e4736
        errors:
          type: array
          description: Each rejected field. Present on field validation errors only.
          items:
            type: object
            properties:
              message:
                type: string
                description: Why the value was rejected.
                example: transferId must be a valid UUID
              location:
                type: string
                description: 'Where the value sits: `body.<field>` or `query.<field>`.'
                example: body.senderAccountId
        code:
          type: string
          description: The stable BTF error code.
          example: BTF-0200
        upstream:
          type: object
          description: >-
            The error that an upstream provider (JD SPB, Midaz) reported. Absent
            unless surfaced.
          properties:
            code:
              type: string
              description: The provider's own error code, verbatim.
              example: AAC90
            message:
              type: string
              description: The provider's own error message, bounded.
              example: Assinatura invalida
        requestId:
          type: string
          description: The request correlation ID. Present even when empty.
          example: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
        service:
          type: string
          description: The system that produced the error.
          example: plugin
        category:
          type: string
          description: The machine-readable error category.
          example: deterministic
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - service
            - category
            - message
            - requestId
          properties:
            code:
              type: string
              description: >-
                The stable error code. Plugin errors use the `BTF-XXXX` format;
                JD SPB business/auth rejections pass through the raw vendor code
                verbatim (e.g. `AAC90`, `ACE95`, `DVE01`), and transport-level
                JD failures surface the synthetic markers `TRANSPORT` or
                `JD_MISSING_CODE`. Match on this value rather than on the HTTP
                status.
              example: BTF-0010
            service:
              type: string
              description: The service or domain that produced the error.
              example: plugin
            category:
              type: string
              description: Machine-readable error category used for retry decisions.
              enum:
                - deterministic
                - transient
                - rate_limit
                - plugin
              example: deterministic
            message:
              type: string
              description: A human-readable error summary.
              example: >-
                Transfers can only be initiated Monday-Friday between 06:30 and
                17:00 Brasília time
            requestId:
              type: string
              description: The request correlation ID. Present even when empty.
              example: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
            fields:
              type: object
              additionalProperties: true
              description: >-
                Structured validation or retry metadata when available.
                Field-level, header, path, and query validation details are all
                returned here.
              example:
                currentTime: '2026-02-01T18:30:00-03:00'
                operatingHours: Mon-Fri 06:30-17:00 UTC-3
  responses:
    Unauthorized:
      description: Indicates that the request is missing a valid authentication token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            unauthorized:
              summary: Missing authorization
              value:
                error:
                  code: BTF-0401
                  service: plugin
                  category: deterministic
                  message: Missing or invalid authentication token
                  requestId: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
    IdempotencyKeyRefused:
      description: >-
        BTF-0014: an earlier request under this `X-Idempotency` key answered
        5xx, so the key is fenced for the retention window. Read the resource
        and, only if the work did not land, send the identical request under a
        new key.


        BTF-0015: this service cannot read the idempotency record under this
        key. The remedy is the same.


        BTF-0017: this `X-Idempotency` key was already used for a different
        request. A repeat must be byte-identical, and a new request needs its
        own new key. BTF-0017 is decided before BTF-0014, so a fenced key resent
        with a changed body gets BTF-0017.
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDocument'
    RateLimitExceeded:
      description: >-
        Indicates that the rate limit has been exceeded. Retry after the number
        of seconds specified in the Retry-After header.
      headers:
        Retry-After:
          description: Seconds until rate limit resets
          schema:
            type: integer
            example: 60
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            rateLimitExceeded:
              summary: Too many requests
              value:
                error:
                  code: BTF-0429
                  service: plugin
                  category: rate_limit
                  message: >-
                    Too many requests. Retry after the interval indicated by the
                    `Retry-After` header.
                  requestId: 6d3e2a68-1f2b-4c3d-9e4f-5a6b7c8d9e0f
              description: >
                Rate-limit responses use the dedicated `BTF-0429` code with the
                `rate_limit` category. Clients should back off using the HTTP
                status `429` and the `Retry-After` header.
  headers:
    XIdempotencyFenced:
      description: >-
        `true` when this 5xx fenced the `X-Idempotency` key, so a resend is
        refused with 422 BTF-0014. `false` when the fence write itself failed
        and only the in-flight lease holds the key, so a resend is refused with
        409 BTF-0016 until that lease lapses. On a 503 BTF-0019, `false` means
        the handler succeeded and both its receipt and its fence were lost.


        The header is absent when nothing fenced the key. On a 500 raised by a
        panic, the protection of the key is unknown: read the resource and
        reconcile before you resend. On a 503 BTF-9000 answered while the
        idempotency store was down before the handler, nothing ran: send the
        same request again under the same key.
      schema:
        type: string
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        JWT Bearer token authentication. The tenantId is derived from the bearer
        token or authenticated request context and is not supplied through
        X-Organization-Id.
    OAuth2ClientCredentials:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: /v1/login/oauth/access_token
          scopes:
            api: TED transfer API access
    OAuth2Password:
      type: oauth2
      flows:
        password:
          tokenUrl: /v1/login/oauth/access_token
          scopes:
            api: TED transfer API access

````