---
id: routes-the-checkout-calls
title: Routes the checkout calls for you
summary: The browser routes the checkout uses on your behalf, for reading and debugging rather than for calling.
faces: ["public", "agent"]
section: front-end
group: Appendix
slug: routes
order: 100
---
# Routes the checkout calls for you

You do not call these. The checkout does, from the shopper's browser, using your publishable key or the
session's client secret. They are written down because a network tab is easier to read when you know what
each request is for, and because an agent reading these docs should not have to guess.

If you want the routes your own server calls, those are in the [API reference](/api/reference).

Everything below is generated from the OpenAPI document, so it cannot drift from the API the checkout
actually calls.

<!-- generated from docs/api/openapi.yaml — edit the spec, not this -->

### POST /v1/checkout/sessions/{session_id}/authenticate

Start card authentication for a session

**Authentication.** The session's client secret. The browser checkout sends this for you.

Opens a payment attempt with the card reference the checkout's card fields produced, and starts
3-D Secure. A retry answers the same attempt. A session allows 3 attempts.

| parameter | in | required | what it is |
|---|---|---|---|
| `session_id` | path | yes | The session's id. |

**Fields in the body you send**

| field | type | always sent | what it is |
|---|---|---|---|
| `card_token` | string | yes | The reference the checkout's card fields produced. Never a card number. |
| `card` | object | yes | What the checkout may say about the card. Never the number. |
| `browser` | object or null | no | What the card scheme needs to know about the shopper’s browser to decide on a challenge. |
| `billing_address` | object or null | no | The shopper’s billing address, when one was collected. |

**`card` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `last4` | string | no | The last four digits, which the shopper recognises. |
| `brand` | string | no | The card scheme. |
| `expiry_month` | integer | no | The expiry month, 1 to 12. |
| `expiry_year` | integer | no | The four-digit expiry year. |

**`browser` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `user_agent` | string | yes | The browser’s user-agent string. |
| `accept_header` | string | yes | The browser’s Accept header. |
| `language` | string | yes | The browser’s language, for example `en-GB`. |
| `colour_depth` | integer | yes | The screen’s colour depth in bits. |
| `screen_height` | integer | yes | The screen height in pixels. |
| `screen_width` | integer | yes | The screen width in pixels. |
| `time_zone_offset_minutes` | integer | yes | The browser’s offset from UTC in minutes. |
| `javascript_enabled` | boolean | yes | Whether JavaScript is available. |
| `java_enabled` | boolean or null | no | Whether Java is available. The card schemes still ask. |
| `trace` | object or null | no |  |
| `channel` | string or null | no | How the payment is being made. Card schemes treat a browser differently from an app. |
| `sdk_version` | string or null | no | Which version of the checkout collected this. |

**`browser.trace` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `session_id` | string | yes |  |
| `device_id` | string or null | no |  |

**`billing_address` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `line1` | string | yes | The first line of the address. |
| `postcode` | string | yes | The postcode. |
| `country` | string | yes | A two-letter ISO 3166-1 country code. |

**200 —** The attempt, and where to show the challenge.

**Fields in the response**

| field | type | always sent | what it is |
|---|---|---|---|
| `status` | string | yes | What to do next: the attempt is done, or it needs the shopper to authenticate. |
| `attempt_id` | string | yes | This attempt. Quote it to us about this one try. |
| `three_ds` | object | yes | What the checkout needs in order to run 3-D Secure, or `null` when none is needed. |
| `amount_verified` | boolean | yes | Whether ripper could check the amount against your price list before charging it. When it could not, an approved payment is held for you to review rather than captured. |

**`three_ds` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `state` | string | yes | Where this authentication has got to. |
| `provider` | string | no | Which 3-D Secure provider is being used. |
| `session_id` | string | no | The provider’s own id for this authentication. |
| `mount` | object | no | What the checkout needs to put the provider’s challenge on the page. |

**When it refuses**

- `400` — `invalid_request` or `card_data_rejected`.
- `401` — `unauthorized`: the client secret is missing or wrong, or the session does not exist.
- `409` — `session_expired`, `session_declined`, `session_completed`, `session_processing` or `attempts_exhausted`.
- `422` — `acquiring_profile_incomplete`: the account is not set up to take live card payments yet.
- `429` — Too many requests from your address in a minute. This answer comes from ripper's gateway, so its body is not the error shape above. Wait for `Retry-After` seconds.
- `500` — `internal_error`: something failed on ripper's side. The body carries no message. Quote `request_id` to support.
- `503` — `three_ds_provider_unavailable`: card authentication is unavailable for a moment. Try again.

Operation id `authenticateCheckoutSession`, for code generators.

### POST /v1/checkout/sessions/{session_id}/confirm

Confirm the payment

**Authentication.** The session's client secret. The browser checkout sends this for you.

Charges the authenticated attempt. A card decline is a 200 with `status: declined`, not an error.
Every payment needs the shopper's email: on the session, or as `customer.email` here. Retrying the
same attempt answers the recorded result.

| parameter | in | required | what it is |
|---|---|---|---|
| `session_id` | path | yes | The session's id. |

**Fields in the body you send**

| field | type | always sent | what it is |
|---|---|---|---|
| `signals` | object | no | Behavioural signals the checkout collects, at most 16 KB. |
| `customer` | object | no | The shopper, when the checkout collected details the session did not already carry. |

**`customer` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `email` | string | no | The shopper’s email address. |

**200 —** The payment's outcome.

**Fields in the response**

| field | type | always sent | what it is |
|---|---|---|---|
| `status` | string | yes | `processing` while the outcome is not known yet; ask again after this response's own `retry_after_seconds`. A PAYMENT MAY BE IN FLIGHT. Asking again is a replay of the same request, never a new one, and starting a second payment here is the mistake this field exists to prevent. An error body carries a field of the same name meaning the opposite — that request created nothing and charged nothing, so sending it again is safe. Branch on the status and the code, not on the field name. On every arm other than `processing` this field is written as `null` rather than omitted, which is the reverse of the error body's convention. |
| `payment_id` | string or null | yes | The payment this confirm produced, or `null` when it produced none. |
| `decline` | object or null | yes | Why the payment was declined, or `null` when it was not. |
| `retry_after_seconds` | integer or null | yes | How long to wait before asking again, in seconds, when the status is `processing`. A PAYMENT MAY BE IN FLIGHT. Asking again is a replay of the same request, never a new one. An error body carries a field of the same name meaning the opposite — that request created nothing and charged nothing, so sending it again is safe. Branch on the status and the code, not on the field name. Written as `null` on every arm other than `processing`, where the error body omits it instead. |
| `settlement` | string or null | yes | Set while an attempt is finished but the outcome has not been reconciled with the acquirer yet; `null` otherwise. Money may already have moved, so do not release goods and do not treat the payment as failed while it is set — reconciliation resolves it, not a clock in the checkout. |
| `amount_verified` | boolean | yes | Whether ripper could check the amount against your price list before charging it. When it could not, an approved payment is held for you to review rather than captured. |
| `hold` | object or null | yes | The hold placed on this payment, or `null` when none was placed. |

**`decline` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `code` | string | yes | The stable decline code. Branch on this. |
| `category` | string | yes | How to treat the decline: `soft`, `hard`, `fraud`, `network` or `provider_error`. Soft is worth another attempt; hard is not. |
| `reason` | string or null | yes | The acquirer’s own words, passed on as received. |

**`hold` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `status` | string | yes | Where the hold is. `pending_review` and `escalated` are both still waiting on a decision — escalated means a person is looking at it rather than a rule. `captured` means the money was taken. `voided` means the hold was released and nothing was taken, and it is final: it is not another kind of waiting. DO NOT RELEASE GOODS until this says `captured`. That holds for all four values, including escalated, which can still end either way. |
| `reason` | string | yes | `no_price_list`: there was nothing to check the amount against. `mismatch`: the amount did not match. |
| `detail` | string or null | yes | More about why, when there is more to say. |
| `deadline` | string | yes | When the hold must be decided by. |
| `decided_by` | string or null | yes | Who decided: you, or ripper on your rules. |
| `decided_at` | string or null | yes | When the decision was made, or `null` while it is still waiting. |
| `operation_refusal` | object or null | yes | The last capture or void the acquirer refused, if any. |

**`hold.operation_refusal` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `kind` | string | yes | Which operation was refused. |
| `sequence` | integer | yes | Which attempt this refusal belongs to. |
| `reason` | string | yes | Why it was refused. |
| `decline_code` | string or null | yes | The decline code, when the refusal came from the acquirer. |
| `at` | string | yes | When the refusal happened. |

**When it refuses**

- `400` — `customer_email_required` (no email on the session or in the body), `invalid_request` or `card_data_rejected`.
- `401` — `unauthorized`: the client secret is missing or wrong, or the session does not exist.
- `409` — `session_expired`, or `authentication_incomplete` with the attempt and challenge to finish (`three_ds.state` is `awaiting_challenge` or `not_started`).
- `429` — Too many requests from your address in a minute. This answer comes from ripper's gateway, so its body is not the error shape above. Wait for `Retry-After` seconds.
- `500` — `internal_error`: something failed on ripper's side. The body carries no message. Quote `request_id` to support.
- `503` — `store_unavailable` or `three_ds_provider_unavailable`.

Operation id `confirmCheckoutSession`, for code generators.

### POST /v1/checkout/public/sessions

Create a checkout session from the browser

How the checkout creates a session when your page has no server-created one. Keyed by the
publishable key in the body; the request's `Origin` must be one of the integration's allowed
origins. The amount is verified against the integration's default or price list where it can be,
and an integration that requires a verified amount refuses one that is not.

| parameter | in | required | what it is |
|---|---|---|---|
| `Rip-Idempotency-Key` | header | yes | A key you choose for this create, for example your order id plus an attempt number. Retrying with the same key and body returns the first response instead of creating a second session. Up to 255 printable ASCII characters. |
| `Origin` | header | yes | The page's origin, which the browser sends. It must be one of the integration's allowed origins. |

**The body you send**

```json
{
  "public_key": "rip_pk_EXAMPLE-KEY_00000000abcZ",
  "amount": 2500,
  "currency": "GBP",
  "customer": {
    "email": "shopper@example.com"
  }
}
```

**Fields in the body you send**

| field | type | always sent | what it is |
|---|---|---|---|
| `public_key` | string | no | Your publishable key. Not used on the hosted payment page route, which finds it through the handle. |
| `integration` | string | no | The integration's name. Without it, the default integration. |
| `amount` | integer | no | The amount, unless items or the integration's default give one. |
| `currency` | string | no | Three letters. Without it, the integration's or account's currency. |
| `items` | array | no | What the shopper is buying. Each needs a positive quantity and a sku or a name. |
| `customer` | object | no | The shopper. Every payment needs an email; if you leave it out, the checkout asks for it. |
| `metadata` | object | no | Up to 50 string values of your own, 8 KB in total. Keys come back exactly as you sent them. |
| `order_reference` | string | no | Your order reference, shown to the shopper on the confirmation page and stored on the payment. |
| `confirmation_url` | string | no | Where to send the shopper after the payment, instead of your integration’s setting. |

**`items` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `sku` | string | no | Your code for the item. A line needs this or a `name`. |
| `name` | string | no | What the shopper sees. A line needs this or a `sku`. |
| `quantity` | integer | yes | How many. |
| `type` | string | no | Your own label for the kind of thing this is. |

**`customer` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `email` | string | no | The shopper’s email address. |
| `name` | string | no | The shopper’s name. |
| `account_created` | string | no | When the shopper’s account with you was created. Card schemes treat a long-standing account as lower risk. |

**201 —** The session was created, or replayed for the same idempotency key.

**Fields in the response**

| field | type | always sent | what it is |
|---|---|---|---|
| `id` | string | yes | The session. Send its `client_secret` to your page; send this to us. |
| `client_secret` | string | yes | Pass this to the checkout on your page. It is returned only here. |
| `status` | string | yes | Where the session is in its life. A new session has taken no attempts yet. |
| `mode` | string | yes | `test` or `live`. A test session can take only test cards. |
| `amount` | integer | yes | What the shopper will be charged, in the currency’s minor unit. |
| `currency` | string | yes | A three-letter ISO 4217 code, for example `GBP`. |
| `public_key` | string | yes | Your publishable key, which the checkout loads the session with. |
| `config_url` | string | yes | The configuration read's path, relative to the API host. |
| `created_at` | string | yes | When the session was created. |
| `expires_at` | string | yes | When the session stops accepting attempts. |
| `expires_in_seconds` | integer | yes | How long the session has from now. |
| `integration` | string | yes | The name of the integration this session was created on: the one you named, or your default integration when you named none. On the hosted payment page it is always that page’s own integration. |
| `amount_verified` | boolean | yes | Whether ripper could check the amount against this integration’s default amount or its price list. When it could not, an approved payment is held for you to review rather than captured. An integration set to require a verified amount refuses the request instead, and no session is created. |
| `amount_verification_source` | string | yes | What the amount was checked against: the integration’s default amount, its price list, nothing at all, or a disagreement with what the integration has configured. The `server_minted` value this field carries on a server-created session never appears here. |
| `amount_verification_detail` | string or null | yes | Why the amount did not verify, when the source is `mismatch`. `null` in every other case, and always sent. |
| `minted_by` | string | yes | Always `client` here: this session was created from the page, not from your server. |

**When it refuses**

- `400` — `idempotency_key_missing`, `invalid_request`, `currency_required`, `metadata_too_large` or `card_data_rejected`.
- `401` — `unauthorized` (the key is malformed, unknown or unusable) or `key_revoked`.
- `403` — `origin_not_allowed`, `merchant_not_active` or `key_live_only`.
- `404` — `resource_not_found`: no integration with the name sent.
- `409` — `idempotency_key_reused`.
- `422` — `amount_unverified`: the integration requires a verified amount and this one could not be verified.
- `429` — Too many requests from your address in a minute. This answer comes from ripper's gateway, so its body is not the error shape above. Wait for `Retry-After` seconds.
- `500` — `internal_error`: something failed on ripper's side. The body carries no message. Quote `request_id` to support.
- `503` — `store_unavailable`.

Operation id `createCheckoutSessionFromBrowser`, for code generators.

### POST /v1/checkout/handles/{handle}/sessions

Create a session for the hosted payment page

The hosted payment page's create. The publishable key is found through the handle, and the hosted
payment page integration is always used. An unknown handle answers `handle_not_found`.

| parameter | in | required | what it is |
|---|---|---|---|
| `handle` | path | yes | Your hosted payment page handle, exactly as registered. |
| `Rip-Idempotency-Key` | header | yes | A key you choose for this create, for example your order id plus an attempt number. Retrying with the same key and body returns the first response instead of creating a second session. Up to 255 printable ASCII characters. |
| `Origin` | header | yes | The page's origin, which the browser sends. It must be one of the integration's allowed origins. |

**Fields in the body you send**

| field | type | always sent | what it is |
|---|---|---|---|
| `public_key` | string | no | Your publishable key. Not used on the hosted payment page route, which finds it through the handle. |
| `integration` | string | no | The integration's name. Without it, the default integration. |
| `amount` | integer | no | The amount, unless items or the integration's default give one. |
| `currency` | string | no | Three letters. Without it, the integration's or account's currency. |
| `items` | array | no | What the shopper is buying. Each needs a positive quantity and a sku or a name. |
| `customer` | object | no | The shopper. Every payment needs an email; if you leave it out, the checkout asks for it. |
| `metadata` | object | no | Up to 50 string values of your own, 8 KB in total. Keys come back exactly as you sent them. |
| `order_reference` | string | no | Your order reference, shown to the shopper on the confirmation page and stored on the payment. |
| `confirmation_url` | string | no | Where to send the shopper after the payment, instead of your integration’s setting. |

**`items` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `sku` | string | no | Your code for the item. A line needs this or a `name`. |
| `name` | string | no | What the shopper sees. A line needs this or a `sku`. |
| `quantity` | integer | yes | How many. |
| `type` | string | no | Your own label for the kind of thing this is. |

**`customer` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `email` | string | no | The shopper’s email address. |
| `name` | string | no | The shopper’s name. |
| `account_created` | string | no | When the shopper’s account with you was created. Card schemes treat a long-standing account as lower risk. |

**201 —** The session was created, or replayed for the same idempotency key.

**Fields in the response**

| field | type | always sent | what it is |
|---|---|---|---|
| `id` | string | yes | The session. Send its `client_secret` to your page; send this to us. |
| `client_secret` | string | yes | Pass this to the checkout on your page. It is returned only here. |
| `status` | string | yes | Where the session is in its life. A new session has taken no attempts yet. |
| `mode` | string | yes | `test` or `live`. A test session can take only test cards. |
| `amount` | integer | yes | What the shopper will be charged, in the currency’s minor unit. |
| `currency` | string | yes | A three-letter ISO 4217 code, for example `GBP`. |
| `public_key` | string | yes | Your publishable key, which the checkout loads the session with. |
| `config_url` | string | yes | The configuration read's path, relative to the API host. |
| `created_at` | string | yes | When the session was created. |
| `expires_at` | string | yes | When the session stops accepting attempts. |
| `expires_in_seconds` | integer | yes | How long the session has from now. |
| `integration` | string | yes | The name of the integration this session was created on: the one you named, or your default integration when you named none. On the hosted payment page it is always that page’s own integration. |
| `amount_verified` | boolean | yes | Whether ripper could check the amount against this integration’s default amount or its price list. When it could not, an approved payment is held for you to review rather than captured. An integration set to require a verified amount refuses the request instead, and no session is created. |
| `amount_verification_source` | string | yes | What the amount was checked against: the integration’s default amount, its price list, nothing at all, or a disagreement with what the integration has configured. The `server_minted` value this field carries on a server-created session never appears here. |
| `amount_verification_detail` | string or null | yes | Why the amount did not verify, when the source is `mismatch`. `null` in every other case, and always sent. |
| `minted_by` | string | yes | Always `client` here: this session was created from the page, not from your server. |

**When it refuses**

- `400` — `idempotency_key_missing`, `invalid_request`, `currency_required`, `metadata_too_large` or `card_data_rejected`.
- `401` — `unauthorized` or `key_revoked`.
- `403` — `origin_not_allowed`, `merchant_not_active` or `key_live_only`.
- `404` — `handle_not_found`.
- `409` — `idempotency_key_reused`.
- `422` — `amount_unverified`.
- `429` — Too many requests from your address in a minute. This answer comes from ripper's gateway, so its body is not the error shape above. Wait for `Retry-After` seconds.
- `500` — `internal_error`: something failed on ripper's side. The body carries no message. Quote `request_id` to support.
- `503` — `store_unavailable`.

Operation id `createHostedPageSession`, for code generators.

### GET /v1/checkout/config/{public_key}

Read the checkout configuration for a publishable key

What the checkout needs to draw itself for your integration. No credential beyond the publishable
key. Cached for 5 minutes and answered with an ETag. An unknown, revoked or unusable key, or an
unknown integration name, all answer the same 404.

| parameter | in | required | what it is |
|---|---|---|---|
| `public_key` | path | yes | Your publishable key, which starts `rip_pk_`. It is safe to put in a web page; only the secret key is not. |
| `integration` | query | no | The integration's name. Without it the default integration is used. |
| `If-None-Match` | header | no | An ETag from an earlier read. A match answers 304. |

**200 —** The configuration.

**Fields in the response**

| field | type | always sent | what it is |
|---|---|---|---|
| `merchant` | object | yes | Who the shopper is paying, as the checkout shows them. |
| `mode` | string | yes | `test` or `live`. A test config can take only test cards. |
| `payment_methods` | array | yes | The payment methods the checkout may offer. |
| `capture` | object | yes | How the card fields load. |
| `three_ds` | object | yes | What the checkout needs in order to run 3-D Secure. |
| `presentation` | object | yes | How the checkout looks, after the integration's own settings are applied. |
| `integration` | object | yes | The integration this config belongs to and the rules it carries. |
| `currency` | string or null | yes | The currency this integration charges in. |
| `config_version` | integer | yes | Changes whenever this config does, so a cached copy can be checked. |

**`merchant` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `display_name` | string | yes | The trading name the shopper sees. |
| `handle` | string or null | yes | Your handle, as registered. |
| `public_key` | string | yes | The publishable key this config was fetched with. |

**`capture` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `sdk_url` | string | yes | Where the checkout loads the card-capture code from. |
| `public_token` | string | yes | The token the card-capture code authenticates with. It cannot take a payment on its own. |
| `init_params` | object | yes | What the card-capture code needs to start. |
| `token_format` | string | yes | The shape of the token the capture returns. |

**`three_ds` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `provider` | string | yes | Which 3-D Secure provider this integration uses. |

**`presentation` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `brand` | object or null | yes | How the checkout is dressed. |
| `layout` | object or null | yes | How the checkout arranges itself. |
| `copy` | object or null | yes | Words of yours that replace the checkout’s own. |
| `extensions` | object or null | yes | Parts of the checkout you can turn on or off. |
| `payment_link` | object or null | yes | How the hosted payment page presents itself, when you use one. |
| `custom_css` | string or null | yes | Your own CSS, applied to the checkout. |
| `presentation_version` | integer | yes | Changes whenever the presentation does, so a cached copy can be checked. |
| `button_label` | string or null | yes |  |

**`presentation.brand` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `logo_url` | string or null | no | Your logo, shown at the top of the checkout. |
| `primary_colour` | string or null | no | The colour the checkout uses for its main action. |
| `accent_colour` | string or null | no | The colour the checkout uses to draw attention to a second thing. |
| `font_family` | string or null | no | The typeface the checkout sets its text in. |
| `favicon_url` | string or null | no | The icon for the hosted payment page’s tab. |

**`presentation.layout` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `card_field_layout` | string | no | Whether the card fields sit on one line or several. |
| `method_display` | string | no | How the payment methods are presented. |
| `step_mode` | string | no | Whether the checkout is one page or a sequence of steps. |
| `density` | string | no | How much space the checkout leaves around its fields. |
| `field_order` | array or null | no | The order the fields are shown in. |

**`presentation.copy` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `cta_text` | string or null | no | What the pay button says. |
| `trust_badge_text` | string or null | no | What the trust badge says. |
| `error_messages` | object or null | no |  |
| `footer_text` | string or null | no | What sits below the form. |

**`presentation.extensions` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `show_order_summary` | boolean | no | Whether the basket is shown beside the form. |
| `show_trust_badges` | boolean | no | Whether the trust badges are shown. |

**`presentation.payment_link` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `hero_image_url` | string or null | no | The image at the top of the hosted page. |
| `headline` | string or null | no | The heading on the hosted page. |
| `description` | string or null | no | The text below the heading on the hosted page. |
| `show_merchant_logo` | boolean | no | Whether your logo is shown on the hosted page. |

**`integration` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `name` | string | yes | The integration’s name, as you registered it. |
| `kind` | string | yes | What kind of integration this is. |
| `theme` | string | yes | Which theme the checkout draws. |
| `mode` | string | yes | `test` keeps every session in test mode. `auto` follows your account. |
| `amount_trust_policy` | string | yes | How far ripper trusts an amount the page supplies. |
| `hold_duration_days` | integer | yes | How long a held payment waits for a decision before it is released. |
| `signals_capture_enabled` | boolean | yes | Whether the checkout collects behavioural signals for this integration. |
| `confirmation_behaviour` | string | yes | What the checkout does once a payment finishes. |
| `defaults` | object | yes | What a page-created session gets when it names no amount or basket of its own. |
| `confirmation_url` | string or null | yes | Where the shopper is sent after the payment, unless a session overrides it. |

**`integration.defaults` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `amount` | integer or null | yes | The default amount, in the currency’s minor unit. |
| `currency` | string or null | yes | The default currency. |
| `items` | array or null | yes | The default basket. This is the browser config’s line shape, which carries no `kind` and no tax — a merchant basket sent from your server is a different, richer line. |

**`integration.defaults.items` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `sku` | string | yes | Your code for the item. |
| `name` | string | yes | What the shopper sees. |
| `quantity` | integer | yes | How many. |
| `unit_amount` | integer | yes | What the shopper pays per unit, in the currency’s minor unit. |

**When it refuses**

- `304` — The configuration has not changed since the ETag you sent.
- `404` — Not found. Since v1.13 this is the ordinary error body — `request_id` in the body as well as the header, and `Cache-Control: no-store` — rather than the bare `{"error": "handle_not_found"}` it used to be. The bare body carried neither, which left a caching layer free to hold on to a 404 that a merchant was in the middle of fixing.
- `429` — Too many requests from your address in a minute. This answer comes from ripper's gateway, so its body is not the error shape above. Wait for `Retry-After` seconds.
- `500` — `internal_error`: something failed on ripper's side. The body carries no message. Quote `request_id` to support.
- `503` — `three_ds_provider_unavailable`: card authentication is unavailable for a moment. Try again.

Operation id `getCheckoutConfig`, for code generators.

### GET /v1/checkout/methods/{public_key}

Read the payment methods for a publishable key

Card is the only method today. Cached for 5 minutes. An unusable key answers 404.

| parameter | in | required | what it is |
|---|---|---|---|
| `public_key` | path | yes | Your publishable key, which starts `rip_pk_`. It is safe to put in a web page; only the secret key is not. |

**200 —** The methods.

```json
{
  "methods": [
    {
      "type": "card",
      "brands": [
        "visa",
        "mastercard",
        "amex"
      ]
    }
  ]
}
```

**Fields in the response**

| field | type | always sent | what it is |
|---|---|---|---|
| `methods` | array | yes | The payment methods this key can take. |

**`methods` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `type` | string | yes | The method. |
| `brands` | array | yes | The card schemes accepted. |

**When it refuses**

- `404` — Not found. Since v1.13 this is the ordinary error body — `request_id` in the body as well as the header, and `Cache-Control: no-store` — rather than the bare `{"error": "handle_not_found"}` it used to be. The bare body carried neither, which left a caching layer free to hold on to a 404 that a merchant was in the middle of fixing.
- `429` — Too many requests from your address in a minute. This answer comes from ripper's gateway, so its body is not the error shape above. Wait for `Retry-After` seconds.
- `500` — `internal_error`: something failed on ripper's side. The body carries no message. Quote `request_id` to support.

Operation id `getCheckoutPaymentMethods`, for code generators.

### GET /v1/checkout/sessions/{session_id}/state

Read the session's state with its client secret

**Authentication.** The session's client secret. The browser checkout sends this for you.

How the checkout resumes a session in the browser, for example after a reload. A wrong secret and
an unknown session answer the same 401. Never cached.

| parameter | in | required | what it is |
|---|---|---|---|
| `session_id` | path | yes | The session's id. |

**200 —** The session's state.

**Fields in the response**

| field | type | always sent | what it is |
|---|---|---|---|
| `id` | string | yes | The session this state belongs to. |
| `status` | string | yes | Where the session is now. Read it after a reload to decide what to show. |
| `expires_in_seconds` | integer | yes | How long the session has left. |
| `attempt_count` | integer | yes | How many payment attempts this session has had. |
| `last_decline` | object or null | yes | The most recent decline on this session, or `null` when there has not been one. |
| `payment_id` | string or null | yes | The payment this session produced, or `null` while it has not produced one. |
| `payment_status` | string or null | yes | The payment’s status, or `null` while there is no payment. |
| `amount_verified` | boolean | yes | Whether ripper could check the amount against your price list before charging it. When it could not, an approved payment is held for you to review rather than captured. |
| `amount_verification_source` | string | yes | What the amount was checked against: the server that created it, the integration’s default, the price list, nothing, or a mismatch. |
| `amount_verification_detail` | string or null | yes | Why the amount did not verify, when the source is a mismatch. `null` otherwise. |
| `hold` | object or null | yes | The hold on this session’s payment, or `null` when there is none. |
| `mount` | object or null | yes | The open challenge to show, if any. |
| `integration` | string or null | yes | Which of your integrations this session belongs to. |
| `minted_by` | string or null | yes | Whether this session was created from your server or from the page. A page-created amount is only as good as what the integration could check it against: `amount_verified` says whether it was, and a payment it could not verify is held for you to review rather than captured. A session your server created is never held for this reason. |
| `amount` | integer | yes | What the shopper will be charged, in the currency’s minor unit. |
| `currency` | string | yes | A three-letter ISO 4217 code, for example `GBP`. |
| `billing_address_present` | boolean | yes | Whether a billing address has been collected. The address itself is never returned here. |
| `customer_email_present` | boolean | yes | Whether an email has been collected. The email itself is never returned here — this says only that there is one. |
| `country` | string or null | yes | The country the checkout is being shown for. |
| `order_reference` | string or null | yes | Your reference for this order, or `null` when none was sent. |
| `confirmation_url` | string or null | yes | The session's own confirmation URL, or else its integration's. |

**`last_decline` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `code` | string | yes | The decline code. |
| `category` | string or null | yes | How to treat the decline: `soft`, `hard`, `fraud`, `network` or `provider_error`. Since v1.13 the word is the same snake_case everywhere — these routes, the webhook and the checkout — where the merchant routes and webhooks previously spelled it `Soft`, `Hard`, `ProviderError` and so on. It is the payment platform's own category, relayed unchanged rather than re-classified here. |
| `reason` | string or null | yes | The acquirer's own words, passed on as received. |

**`hold` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `status` | string | yes | Where the hold is. `pending_review` and `escalated` are both still waiting on a decision — escalated means a person is looking at it rather than a rule. `captured` means the money was taken. `voided` means the hold was released and nothing was taken, and it is final: it is not another kind of waiting. DO NOT RELEASE GOODS until this says `captured`. That holds for all four values, including escalated, which can still end either way. |
| `reason` | string | yes | `no_price_list`: there was nothing to check the amount against. `mismatch`: the amount did not match. |
| `detail` | string or null | yes | More about why, when there is more to say. |
| `deadline` | string | yes | When the hold must be decided by. |
| `decided_by` | string or null | yes | Who decided: you, or ripper on your rules. |
| `decided_at` | string or null | yes | When the decision was made, or `null` while it is still waiting. |
| `operation_refusal` | object or null | yes | The last capture or void the acquirer refused, if any. |

**`hold.operation_refusal` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `kind` | string | yes | Which operation was refused. |
| `sequence` | integer | yes | Which attempt this refusal belongs to. |
| `reason` | string | yes | Why it was refused. |
| `decline_code` | string or null | yes | The decline code, when the refusal came from the acquirer. |
| `at` | string | yes | When the refusal happened. |

**When it refuses**

- `401` — `unauthorized`: the client secret is missing or wrong, or the session does not exist.
- `429` — Too many requests from your address in a minute. This answer comes from ripper's gateway, so its body is not the error shape above. Wait for `Retry-After` seconds.
- `500` — `internal_error`: something failed on ripper's side. The body carries no message. Quote `request_id` to support.

Operation id `getCheckoutSessionState`, for code generators.

### GET /v1/checkout/handles/{handle}

Read the hosted payment page configuration for a handle

Used by the hosted payment page at `pay.ripper.dev/{handle}`. Answers the same body as the
configuration read, for your hosted payment page integration. The handle must match exactly.

| parameter | in | required | what it is |
|---|---|---|---|
| `handle` | path | yes | Your hosted payment page handle, exactly as registered. |
| `If-None-Match` | header | no | An ETag from an earlier read. A match answers 304. |

**200 —** The hosted payment page's configuration.

**Fields in the response**

| field | type | always sent | what it is |
|---|---|---|---|
| `merchant` | object | yes | Who the shopper is paying, as the checkout shows them. |
| `mode` | string | yes | `test` or `live`. A test config can take only test cards. |
| `payment_methods` | array | yes | The payment methods the checkout may offer. |
| `capture` | object | yes | How the card fields load. |
| `three_ds` | object | yes | What the checkout needs in order to run 3-D Secure. |
| `presentation` | object | yes | How the checkout looks, after the integration's own settings are applied. |
| `integration` | object | yes | The integration this config belongs to and the rules it carries. |
| `currency` | string or null | yes | The currency this integration charges in. |
| `config_version` | integer | yes | Changes whenever this config does, so a cached copy can be checked. |

**`merchant` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `display_name` | string | yes | The trading name the shopper sees. |
| `handle` | string or null | yes | Your handle, as registered. |
| `public_key` | string | yes | The publishable key this config was fetched with. |

**`capture` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `sdk_url` | string | yes | Where the checkout loads the card-capture code from. |
| `public_token` | string | yes | The token the card-capture code authenticates with. It cannot take a payment on its own. |
| `init_params` | object | yes | What the card-capture code needs to start. |
| `token_format` | string | yes | The shape of the token the capture returns. |

**`three_ds` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `provider` | string | yes | Which 3-D Secure provider this integration uses. |

**`presentation` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `brand` | object or null | yes | How the checkout is dressed. |
| `layout` | object or null | yes | How the checkout arranges itself. |
| `copy` | object or null | yes | Words of yours that replace the checkout’s own. |
| `extensions` | object or null | yes | Parts of the checkout you can turn on or off. |
| `payment_link` | object or null | yes | How the hosted payment page presents itself, when you use one. |
| `custom_css` | string or null | yes | Your own CSS, applied to the checkout. |
| `presentation_version` | integer | yes | Changes whenever the presentation does, so a cached copy can be checked. |
| `button_label` | string or null | yes |  |

**`presentation.brand` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `logo_url` | string or null | no | Your logo, shown at the top of the checkout. |
| `primary_colour` | string or null | no | The colour the checkout uses for its main action. |
| `accent_colour` | string or null | no | The colour the checkout uses to draw attention to a second thing. |
| `font_family` | string or null | no | The typeface the checkout sets its text in. |
| `favicon_url` | string or null | no | The icon for the hosted payment page’s tab. |

**`presentation.layout` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `card_field_layout` | string | no | Whether the card fields sit on one line or several. |
| `method_display` | string | no | How the payment methods are presented. |
| `step_mode` | string | no | Whether the checkout is one page or a sequence of steps. |
| `density` | string | no | How much space the checkout leaves around its fields. |
| `field_order` | array or null | no | The order the fields are shown in. |

**`presentation.copy` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `cta_text` | string or null | no | What the pay button says. |
| `trust_badge_text` | string or null | no | What the trust badge says. |
| `error_messages` | object or null | no |  |
| `footer_text` | string or null | no | What sits below the form. |

**`presentation.extensions` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `show_order_summary` | boolean | no | Whether the basket is shown beside the form. |
| `show_trust_badges` | boolean | no | Whether the trust badges are shown. |

**`presentation.payment_link` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `hero_image_url` | string or null | no | The image at the top of the hosted page. |
| `headline` | string or null | no | The heading on the hosted page. |
| `description` | string or null | no | The text below the heading on the hosted page. |
| `show_merchant_logo` | boolean | no | Whether your logo is shown on the hosted page. |

**`integration` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `name` | string | yes | The integration’s name, as you registered it. |
| `kind` | string | yes | What kind of integration this is. |
| `theme` | string | yes | Which theme the checkout draws. |
| `mode` | string | yes | `test` keeps every session in test mode. `auto` follows your account. |
| `amount_trust_policy` | string | yes | How far ripper trusts an amount the page supplies. |
| `hold_duration_days` | integer | yes | How long a held payment waits for a decision before it is released. |
| `signals_capture_enabled` | boolean | yes | Whether the checkout collects behavioural signals for this integration. |
| `confirmation_behaviour` | string | yes | What the checkout does once a payment finishes. |
| `defaults` | object | yes | What a page-created session gets when it names no amount or basket of its own. |
| `confirmation_url` | string or null | yes | Where the shopper is sent after the payment, unless a session overrides it. |

**`integration.defaults` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `amount` | integer or null | yes | The default amount, in the currency’s minor unit. |
| `currency` | string or null | yes | The default currency. |
| `items` | array or null | yes | The default basket. This is the browser config’s line shape, which carries no `kind` and no tax — a merchant basket sent from your server is a different, richer line. |

**`integration.defaults.items` fields**

| field | type | always sent | what it is |
|---|---|---|---|
| `sku` | string | yes | Your code for the item. |
| `name` | string | yes | What the shopper sees. |
| `quantity` | integer | yes | How many. |
| `unit_amount` | integer | yes | What the shopper pays per unit, in the currency’s minor unit. |

**When it refuses**

- `304` — Not changed since the ETag you sent.
- `404` — Not found. Since v1.13 this is the ordinary error body — `request_id` in the body as well as the header, and `Cache-Control: no-store` — rather than the bare `{"error": "handle_not_found"}` it used to be. The bare body carried neither, which left a caching layer free to hold on to a 404 that a merchant was in the middle of fixing.
- `429` — Too many requests from your address in a minute. This answer comes from ripper's gateway, so its body is not the error shape above. Wait for `Retry-After` seconds.
- `500` — `internal_error`: something failed on ripper's side. The body carries no message. Quote `request_id` to support.
- `503` — `three_ds_provider_unavailable`: card authentication is unavailable for a moment. Try again.

Operation id `getHostedPageConfig`, for code generators.

<!-- end generated -->
