> For the complete documentation index, see [llms.txt](https://plexo.gitbook.io/rest-api/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://plexo.gitbook.io/rest-api/operations/callbacks.md).

# Callbacks Guide

Use callback URLs to receive asynchronous payment and session updates.

## Overview

The public REST contract documents request-scoped callbacks:

* Payment callbacks through `PaymentRequestDto.callbackUrl`
* Checkout session callbacks through `settings.callbacks.paymentCallbackUrl`
* Tokenization session callbacks through `settings.callbacks.tokenizationCallbackUrl`

This documentation does not treat merchant-wide callback registration, shared callback secrets, or signature headers as part of the public API contract.

Use this guide only for request-scoped callbacks that you send as part of payments or sessions.

## Payment Callbacks

Send `callbackUrl` when creating a payment if your system needs an asynchronous notification.

The callback body is a `PaymentDto`.

The payment `id` is a compact GUID string of 32 lowercase hexadecimal characters without hyphens. Non-null `sessionId` and `paymentLinkId` use the same format, just as in payment responses. Use string properties in your callback DTO, or a tested custom JSON converter if you retain `Guid` properties. See [consumer identifier handling](/rest-api/api-reference/models.md#paymentdto).

For new payments from a saved payment link or Quick Pay, `paymentLinkId` identifies the originating link. It is server-assigned and nullable for unrelated or historical payments. A Quick Pay buyer's optional invoice/reference is returned as `metadata.buyerReference`. See [PaymentDto](/rest-api/api-reference/models.md#paymentdto).

Current wallet payment callbacks retain camelCase and expose available recognition hints at `paymentMethod.card.metadata.display_name` and `paymentMethod.card.metadata.display_last4`. Only these two safe display keys enter the card dictionary. Missing keys are omitted; if neither exists, `card.metadata` is omitted. Processing `last4` is unchanged. See the [wallet payment response fragment](/rest-api/payments/payment-processing/create-payment.md#read-the-response). These client-provided hints are not authenticated or guaranteed physical-card identity. Legacy transaction and VTEX callback formats are unchanged.

```http
POST /v1/payments
Authorization: Basic {credentials}
Content-Type: application/json

{
  "merchantId": 12345,
  "referenceId": "order-1001",
  "invoiceNumber": "INV-1001",
  "amount": {
    "total": 10000,
    "currency": "UYU"
  },
  "paymentMethod": {
    "source": "card",
    "card": {
      "number": "4444333322221111",
      "expMonth": 12,
      "expYear": 2028,
      "cvc": "123",
      "cardholder": {
        "firstName": "Test",
        "lastName": "User",
        "email": "customer@example.com"
      }
    }
  },
  "capture": {
    "method": "automatic"
  },
  "callbackUrl": "https://merchant.example.com/callbacks/payments"
}
```

Use `GET /v1/payments/{paymentId}` if you need to confirm the canonical final resource state after receiving a callback.

## Checkout Session Callbacks

Use session callbacks when the customer is completing a hosted checkout flow.

The callback body is the same `PaymentDto` payload used by payment callbacks.

```http
POST /v1/sessions
Authorization: Basic {credentials}
Content-Type: application/json

{
  "merchantId": 12345,
  "referenceId": "checkout-session-1001",
  "type": "checkout",
  "paymentRequest": {
    "referenceId": "order-1001",
    "invoiceNumber": "INV-1001",
    "amount": {
      "total": 10000,
      "currency": "UYU"
    }
  },
  "settings": {
    "callbacks": {
      "paymentCallbackUrl": "https://merchant.example.com/callbacks/checkout"
    }
  }
}
```

## Tokenization Session Callbacks

Use a tokenization callback when the hosted flow is saving an instrument for later use.

The callback body is not a `PaymentDto`. Tokenization sessions use a tokenization-specific callback payload.

```http
POST /v1/sessions
Authorization: Basic {credentials}
Content-Type: application/json

{
  "merchantId": 12345,
  "referenceId": "tokenization-session-1001",
  "type": "tokenization",
  "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "settings": {
    "tokenization": {
      "type": "store"
    },
    "callbacks": {
      "tokenizationCallbackUrl": "https://merchant.example.com/callbacks/tokenization"
    }
  }
}
```

### Tokenization callback payload

Plexo sends the callback to `settings.callbacks.tokenizationCallbackUrl` as an HTTP `POST` with an `application/json` body. The tokenization callback uses PascalCase property names, as shown below.

Plexo sends this callback after successful creation or selection of a payment instrument token. Tokenization failures do not produce a tokenization session callback.

```json
{
  "IsSuccess": true,
  "Created": 1788436800,
  "ErrorCode": null,
  "ErrorType": null,
  "Message": null,
  "Params": null,
  "Data": {
    "Customer": {
      "Id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "ReferenceId": "customer-1001",
      "Metadata": null,
      "Description": null,
      "Email": "customer@example.com",
      "Name": "Test User",
      "Phone": null,
      "FirstName": "Test",
      "LastName": "User",
      "Document": null,
      "Identification": null,
      "Birthdate": null,
      "Address": null,
      "Shipping": null,
      "Status": "active"
    },
    "PaymentInstrument": {
      "ClientId": 1001,
      "PaymentMethodId": "2dcb5f6b-7ca7-4e74-a352-56258c00300c",
      "PaymentMethodType": "card",
      "TokenizationType": "store",
      "Status": "active",
      "Token": "7f49b7dc-d07a-4437-9ff6-475004147caa",
      "Source": "card",
      "Bin": "444433",
      "Last4": "1111",
      "ExpMonth": 12,
      "ExpYear": 2028,
      "CardName": "************1111",
      "CardholderName": "Test User",
      "CardType": "credit",
      "CardOrigin": null,
      "PaymentProcessor": null,
      "Issuer": null,
      "ExpiresAt": null,
      "UsedAt": null,
      "LastAttemptAt": null,
      "CustomerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "CreatedAt": "2026-09-03T12:00:00Z",
      "UniqueIdAlias": null,
      "Metadata": null,
      "CvcCache": {
        "Cached": true,
        "ExpiresAt": "2026-09-03T12:05:00Z"
      }
    }
  },
  "Type": "tokenization-callback"
}
```

| Field                                           | Type                                                                                       | Description                                                                    |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ |
| `IsSuccess`                                     | boolean                                                                                    | `true` for the current tokenization session callback flow.                     |
| `Created`                                       | integer                                                                                    | Callback creation time as a Unix timestamp in seconds.                         |
| `ErrorCode`                                     | object or null                                                                             | Reserved error details with `Name`, `Id`, and `Description`; currently `null`. |
| `ErrorType`                                     | object or null                                                                             | Reserved error category with `Name` and `Id`; currently `null`.                |
| `Message`                                       | string or null                                                                             | Result message, when present.                                                  |
| `Params`                                        | object or null                                                                             | Reserved field-level details; currently `null`.                                |
| `Data`                                          | object                                                                                     | Successful tokenization result.                                                |
| `Data.Customer`                                 | [CustomerDto](/rest-api/api-reference/models.md#customerdto) or null                       | Customer associated with the tokenization session, when present.               |
| `Data.PaymentInstrument`                        | [PublicPaymentInstrumentDto](/rest-api/api-reference/models.md#publicpaymentinstrumentdto) | Created or selected payment instrument token when `IsSuccess` is `true`.       |
| `Data.PaymentInstrument.Metadata.display_name`  | string, when present                                                                       | Optional normalized wallet recognition label, not verified card identity.      |
| `Data.PaymentInstrument.Metadata.display_last4` | string, when present                                                                       | Optional four-ASCII-digit wallet suffix; leading zeros preserved.              |
| `Data.PaymentInstrument.CvcCache.Cached`        | boolean                                                                                    | Whether verification data was available when the callback was created.         |
| `Data.PaymentInstrument.CvcCache.ExpiresAt`     | datetime or null                                                                           | Original UTC cache expiration; callback delivery does not extend it.           |
| `Type`                                          | string                                                                                     | Callback discriminator. Its value is `tokenization-callback`.                  |

{% hint style="info" %}
The linked API model schemas describe the nested fields and their types. API endpoint schemas use camelCase, but the tokenization callback sends those nested property names in PascalCase, as shown in the callback example.
{% endhint %}

{% hint style="warning" %}
The callback contains a reusable payment instrument token and may contain customer data. Receive it only on your backend over HTTPS, restrict access to the payload, and do not write the token or customer data to logs.
{% endhint %}

`CvcCache` is included for both `temporal` and `store` tokens, including selection of an existing saved card. For card CVV, the cache lasts five minutes from entry or update. Check both `Cached` and `ExpiresAt`: the cache may have expired by the time the callback arrives. If unavailable or expired, use the payment method's `settings.securityCode.required` to decide whether to request CVV. The callback never contains the CVV itself. This expiration is separate from the payment instrument token's expiration.

For a wallet instrument with available hints, the following fragment replaces the instrument's `Metadata: null` in the example above (other existing instrument metadata can also be present):

```json
{
  "Data": {
    "PaymentInstrument": {
      "Metadata": {
        "display_name": "Visa •••• 0027",
        "display_last4": "0027"
      }
    }
  }
}
```

Preserve `Data.PaymentInstrument.Metadata` casing and the literal dictionary keys. Missing display keys remain absent. For wallet UI, use only normalized `display_last4`; do not fall back to processing `Last4` or derive digits from `display_name`. Historical instruments may have no hints. See [wallet display hints](/rest-api/customers-and-saved-methods/tokenization-guide.md#wallet-display-hints).

{% hint style="info" %}
If you are tokenizing Google Pay or Apple Pay tokens with your own UI, you can use `POST /v1/tokenizations` instead of hosted sessions. The direct endpoint returns the token synchronously, so you do not need a callback URL. See the [Tokenization Guide](/rest-api/customers-and-saved-methods/tokenization-guide.md#direct-wallet-tokenization-google-pay--apple-pay) for details.
{% endhint %}

## Implementation Guidance

* Return a `2xx` response quickly from your callback endpoint
* Treat callbacks as asynchronous signals, then fetch the resource again if you need confirmation
* Make your callback handling idempotent, because retries can happen in distributed systems
* Keep callback URLs stable and HTTPS-only
* Do not expect a documented public signature header unless Plexo provides one for your specific integration

## Related Resources

* [Payment Processing](/rest-api/payments/payment-processing.md)
* [Tokenization Guide](/rest-api/customers-and-saved-methods/tokenization-guide.md)
* [SessionRequest](/rest-api/api-reference/models.md#sessionrequest)
* [PaymentRequestDto](/rest-api/api-reference/models.md#paymentrequestdto)
* [OCA Pay (limited beta): attempts, authoritative confirmation, and expiry](/rest-api/wallets/oca-pay.md)
