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

# Continue After a 3DS Challenge

> Resume a payment paused for a 3DS challenge. Pass the sessionId from the pending_3ds response. No API key required.

When a purchase or authorization returns `status: "pending_3ds"`, the cardholder must complete a 3D Secure challenge at the URL provided in `actionRequired.url`. Once the cardholder finishes the challenge, call `POST /payment/resume` to continue processing the payment and receive the final outcome.

## How 3DS resumption works

1. Your purchase or authorization call returns `status: "pending_3ds"` with an `actionRequired` object.
2. Redirect the cardholder (or open an iframe) to `actionRequired.url`.
3. After the challenge completes, the cardholder is redirected back to your site.
4. You call `POST /payment/resume` with the `sessionId` to get the final payment result.

<Note>
  No API key is required for this endpoint. The `sessionId` itself acts as the credential and is scoped to a single pending payment. Sessions expire **15 minutes** after the 3DS challenge is issued — if the session has expired, the original purchase or authorization must be retried.
</Note>

<Warning>
  This endpoint handles `pending_3ds` only. It does **not** handle `pending_ddc` (device data collection). For DDC flows, retry the original purchase or authorization request with `threeDsSetup.sessionId` set to the DDC session ID.
</Warning>

The response is a full [payment response](/api-reference/purchase#response) with the final `status`, `refusalCode` on decline, and everything else — same shape as `purchase`/`authorization`.

### Resume after a 3DS challenge

**Expired session — `400 Bad Request`**

```json theme={"dark"}
{
  "error": "session_expired",
  "message": "The 3DS session has expired. Please restart the payment."
}
```

<Tip>
  If you use the Therius JS SDK, you don't need to call this endpoint manually. Call `sdk.handleAction(result.actionRequired)` after receiving a `pending_3ds` response and the SDK handles the redirect, listens for the challenge completion, and resumes the payment automatically. It returns a promise that resolves to the final `paymentResponse`.
</Tip>

<RequestExample>
  ```bash cURL theme={"dark"}
  curl -X POST https://api.therius.io/v1/payment/resume \
    -H "Authorization: Bearer prv_production_your_key_here" \
    -H "Content-Type: application/json" \
    -d '{ "sessionId": "<sessionId from pending_3ds response>" }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={"dark"}
  {
    "status": "captured",
    "paymentCode": "PC-1234567890",
    "orderCode": "ORDER-20240101-001",
    "merchantCode": "MERCHANT_001",
    "amount": { "currency": "USD", "value": 4999, "exponent": 2 },
    "card": {
      "cardData": { "brand": "visa", "cardNumber": "411111****1111", "type": "credit" },
      "networkTransactionId": "txn_abc123"
    },
    "authorizationCode": "AUTH-789"
  }
  ```
</ResponseExample>


## OpenAPI

````yaml POST /payment/resume
openapi: 3.1.0
info:
  title: Therius API
  description: REST API for payments, subscriptions, and billing plans.
  version: 1.0.0
servers:
  - url: https://api.therius.io/v1
    description: Production
  - url: https://api-sandbox.therius.io/v1
    description: Sandbox
security:
  - bearerAuth: []
paths:
  /payment/resume:
    post:
      tags:
        - Payments
      summary: Continue after 3DS challenge
      operationId: resumePayment
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - sessionId
              properties:
                sessionId:
                  type: string
                  description: >-
                    The `sessionId` from a `pending_3ds` / `pending_action`
                    payment response.
      responses:
        '200':
          description: Resumed payment result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentResponse'
      security: []
components:
  schemas:
    PaymentResponse:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: >-
            The Therius payment id. Returned by `POST /payment/authorization`
            and `POST /payment/purchase`; use it as the `{id}` path segment for
            capture, refund, cancel and cancel_or_refund.
          example: 9f8b2c1e-4d5a-6b7c-8d9e-0f1a2b3c4d5e
        status:
          $ref: '#/components/schemas/PaymentStatus'
        paymentCode:
          type: string
          description: >-
            Therius receipt ID, for reconciliation, support and Inquiry. NOT the
            handle for capture/refund/cancel — use `id` for that.
          example: PC-1234567890
        orderCode:
          type: string
          description: Your `orderCode`, echoed back.
        merchantCode:
          type: string
          description: Your `merchantCode`, echoed back.
        autorizationCode:
          type: string
          description: >-
            Issuer authorization code on an approved payment. The field name is
            misspelled on the wire (no `h`) - this is intentional and stable.
        paymentMethod:
          type: string
          description: Payment method used, e.g. `card`, `pix`, `ach`.
        connectionCode:
          type: string
          description: Code of the gateway connection that processed the payment.
        connectionName:
          type: string
          description: Display name of the gateway connection that processed the payment.
        amount:
          $ref: '#/components/schemas/Amount'
        card:
          type: object
          description: >-
            Card details from the response: masked PAN, brand, type, and the
            network transaction/reference IDs to cite on future MIT charges.
        apm:
          type: object
          description: >-
            Alternative-payment-method details (redirect URL, QR code, barcode)
            when `paymentMethod` is an APM.
        token:
          type: object
          description: 'Present when the card was tokenized (`tokenize: true`).'
          properties:
            id:
              type: string
              description: Token ID to use in future `tokenData` charges.
            expirationDate:
              type: string
              description: Token expiry date.
        actionRequired:
          $ref: '#/components/schemas/ActionRequired'
        refusalCode:
          $ref: '#/components/schemas/RefusalCode'
    PaymentStatus:
      type: string
      enum:
        - captured
        - authorized
        - declined
        - pending_3ds
        - pending_action
        - failed
        - cancelled
        - refunded
      description: >-
        `captured` - funds settled; `authorized` - funds reserved, call capture
        to settle; `declined` - issuer declined, see `refusalCode`;
        `pending_3ds` - a 3DS challenge is required, see `actionRequired`;
        `pending_action` - an external action (redirect, voucher) is required,
        see `actionRequired`; `failed` - processing error unrelated to the
        issuer; `cancelled` - authorization voided; `refunded` - captured funds
        returned.
    Amount:
      type: object
      required:
        - currency
        - value
        - exponent
      properties:
        currency:
          type: string
          description: >-
            ISO 4217 currency code. On capture, refund and cancel it must match
            the currency of the original payment.
          example: USD
        value:
          type: integer
          description: >-
            Amount in minor units (cents, pence, etc.). `4999` = $49.99 for USD
            (exponent 2); `5000` = ¥5000 for JPY (exponent 0). On capture it
            must not exceed the authorized value; on refund the cumulative total
            across refunds must not exceed the captured amount.
          example: 4999
        exponent:
          type: integer
          description: >-
            Number of decimal places for the currency — `2` for USD/EUR, `0` for
            JPY. Determines where the decimal point sits in `value`.
          example: 2
    ActionRequired:
      type: object
      description: >-
        Present when `status` is `pending_3ds` or `pending_action`. Describes
        what the cardholder must do next — with the Therius JS SDK, pass the
        whole object to `sdk.handleAction()`.
      properties:
        type:
          type: string
          description: Action type, e.g. `redirect`, `barcode`.
        url:
          type: string
          description: >-
            URL to send the cardholder to for a 3DS challenge or external APM
            flow.
        paymentCode:
          type: string
          description: Therius payment code tied to this pending action.
        barcode:
          type: string
          description: Barcode value for APMs that require it (e.g. Boleto).
        params:
          type: object
          description: Additional parameters required to complete the action.
    RefusalCode:
      type: object
      description: >-
        Present when `status` is `declined`. See the Declined Payments concept
        page for the full code table and how to react to each `recoveryAction`.
      properties:
        reason:
          type: string
          description: Human-readable meaning of `reasonCode`.
          example: Insufficient funds
        reasonCode:
          type: string
          description: >-
            Normalized ISO 8583 decline code. Every provider decline is mapped
            to this set, so handling logic is provider-independent. Full table
            with meanings on the Declined Payments concept page.
          example: '51'
          enum:
            - '1'
            - '2'
            - '3'
            - '4'
            - '5'
            - '6'
            - '7'
            - '8'
            - '9'
            - '11'
            - '12'
            - '13'
            - '14'
            - '15'
            - '16'
            - '17'
            - '19'
            - '20'
            - '21'
            - '22'
            - '25'
            - '28'
            - '30'
            - '41'
            - '43'
            - '46'
            - '51'
            - '52'
            - '53'
            - '54'
            - '55'
            - '57'
            - '58'
            - '59'
            - '61'
            - '62'
            - '63'
            - '65'
            - '68'
            - '75'
            - '76'
            - '77'
            - '78'
            - '80'
            - '81'
            - '82'
            - '83'
            - '85'
            - '91'
            - '92'
            - '93'
            - '94'
            - '95'
            - '96'
            - B1
            - N0
            - N3
            - N4
            - N7
            - P2
            - P5
            - P6
            - Q1
            - R0
            - R1
            - R3
            - XA
            - XD
            - Z3
        originalReason:
          type: string
          description: >-
            Raw message the underlying provider returned, before normalization.
            Diagnostic only — format is not stable across providers.
        originalReasonCode:
          type: string
          description: >-
            Raw code the underlying provider returned, before normalization.
            Diagnostic only — format varies by provider.
        recoveryAction:
          type: string
          description: >-
            What the checkout should do next: `retry` (transient/technical —
            same card may be retried once), `switch_method` (this card will not
            work — prompt for another method), `terminal` (hard block — do not
            retry or offer an alternative).
          enum:
            - retry
            - switch_method
            - terminal
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Your secret API key: `Bearer prv_production_xxx` (production) or `Bearer
        prv_sandbox_xxx` (sandbox).

````