# Card Payments

To use this capability, add `octo/cardPayments` to your `Octo-Capabilities` header.

This capability allows you to accept card payments via the API.

Gateway IDs returned/accepted in source are:

* `adyen`
* `external`

## Endpoints

All paths below are under `/octo`.

This capability extends booking/order/gift write flows and related read flows documented in:

* [Bookings](https://docs.ventrata.com/octo-core/bookings#endpoints)
* [Multi-Booking Cart](https://docs.ventrata.com/capabilities/cart)
* [Gift Vouchers](https://docs.ventrata.com/capabilities/gift-vouchers)

List routes intentionally omit `cardPayment`/`returnUrl`.

{% openapi src="<https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media>" path="/card\_payments/{cardPaymentId}" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Validation rules from source:

* `cardPayment.source` must be one of `POS`, `ECOM`, `MOTO` (`GATEWAY_INVALID_SOURCE` otherwise).
* `cardPayment.currency` must match the order currency (`GATEWAY_CURRENCY_MISMATCH` otherwise).
* If `cardPayment.cardId` is supplied it must reference a reusable card on the selected gateway (`INVALID_CARD_ID` otherwise).
* If an explicit gateway is supplied and does not match the resolved gateway, source raises `GATEWAY_MISMATCH`.

## Response Fields

All card payment request/response fields (including `reusableCards[]` and gateway payloads) are included on the card payment schemas in this page.

Notes:

* `adyen` can return `{}` when `amount <= 0`.
* The card payment lookup endpoint returns cached card payment JSON (up to 1 hour) and is only available when the card payment object was created with a `returnUrl`.

## Adyen Gateway

{% embed url="<https://docs.adyen.com/online-payments/build-your-integration?platform=Web&integration=Drop-in&version=5.43.0>" %}
Adyen Drop-in Integration Docs
{% endembed %}

`session` is `null` until you set a `returnUrl` (for `ECOM` payments).

When you confirm/replay payment, source accepts:

* `adyen.sessionId`
* `adyen.sessionResult` (optional with sessionId)
* `adyen.pspReference`
* `adyen.paymentMethod`
* `adyen.channel`

For Adyen session creation, channel is resolved from the `adyen-channel` request header first, then `cardPayment.adyen.channel`, then defaults to `Web`.

Most integrations send this payload on the booking/order/gift confirm route that finalizes payment.

If Ventrata has not yet received the webhook notification from Adyen then you may receive a `PAYMENT_PENDING` error code. Repeat the request. If the payment is refused, you get a `BAD_REQUEST` error with the reason in `errorMessage`.

## External Gateway

The external gateway lets you register a virtual card payment taken on an external processor.

`external.approved` defaults to `true` when omitted. For external payload processing, source requires at least one of `notes`, `amount`, `currency`, or `cancel` to be present.

## Reusable Cards

Reusable card fields are included in the `ReusableCard` schema.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "cardPayment": {
    "status": "CONFIRMED",
    "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
    "cardPaymentId": "cp_20260514_42ad10",
    "gateway": "adyen",
    "source": "POS",
    "paid": 2200,
    "totalPaid": 2200,
    "totalRefunded": 0,
    "paidSurcharge": 0,
    "balance": 0,
    "surcharge": 0,
    "outstandingBalance": 0,
    "amount": 2200,
    "currency": "USD",
    "currencyPrecision": 2,
    "reusableCards": [
      {
        "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
        "brand": "visa",
        "bin": "411111",
        "last4": "1111"
      }
    ],
    "adyen": {
      "environment": "test",
      "clientKey": "test_client_key_123",
      "session": {
        "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
        "sessionData": "session_data_payload"
      },
      "countryCode": "US"
    },
    "external": {},
    "provider": "adyen",
    "providerReference": "PROV-REF-2026-001",
    "createdAt": "2026-05-14T13:00:00Z"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "cardPayment": {
    "gateway": "adyen"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `Error`

```json
{
  "// ...rest of error object": "...",
  "cardPaymentId": "cp_20260514_42ad10"
}
```

### `Gift`

```json
{
  "// ...rest of gift object": "...",
  "cardPayment": {
    "id": "f1a5d2e8-8d57-4f0b-9c3f-6a12d7a8bc90",
    "gateway": "external",
    "status": "PENDING"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `GiftCreateRequest`

```json
{
  "// ...rest of gift create request object": "...",
  "cardPayment": {
    "gateway": "external",
    "external": {
      "approved": true
    }
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `Order`

```json
{
  "// ...rest of order object": "...",
  "cardPayment": {
    "id": "f1a5d2e8-8d57-4f0b-9c3f-6a12d7a8bc90",
    "gateway": "adyen",
    "status": "PENDING"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `OrderCreateRequest`

```json
{
  "// ...rest of order create request object": "...",
  "cardPayment": {
    "gateway": "adyen"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `OrderUpdateRequest`

```json
{
  "// ...rest of order update request object": "...",
  "cardPayment": {
    "gateway": "adyen"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```
