# Start a hosted checkout for a payer

`POST /checkout-sessions` · Skerry · Accepting payments

Start a hosted checkout for a payer. `payment_instructions` adds stablecoin and bank transfer: the session then carries a deposit address and bank details with a reference to quote, and completes when the money arrives. A customer without card acceptance can open a session that has instructions only.

- Scope: payments:write
- Moves money: yes
- Idempotency: optional
- Untrusted: reference, external_ref, metadata

## Parameters

- `Idempotency-Key` (header), string: A repeat with the same key and body returns the first answer instead of acting twice.

## Request body

`application/json`

```json
{
  "type": "object",
  "required": [
    "customer_id",
    "currency"
  ],
  "properties": {
    "customer_id": {
      "type": "string",
      "maxLength": 200
    },
    "amount": {
      "type": "integer",
      "minimum": 1,
      "description": "Integer minor units of `currency`. Send this or `line_items`."
    },
    "line_items": {
      "type": "array",
      "minItems": 1,
      "maxItems": 50,
      "items": {
        "type": "object",
        "required": [
          "name",
          "amount"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "amount": {
            "type": "integer",
            "minimum": 1,
            "description": "Integer minor units of `currency`, for one unit."
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000
          },
          "description": {
            "type": "string",
            "maxLength": 500
          }
        }
      }
    },
    "currency": {
      "type": "string",
      "pattern": "^[A-Za-z]{3}$"
    },
    "success_url": {
      "type": "string",
      "format": "uri",
      "description": "Required for a hosted card checkout."
    },
    "cancel_url": {
      "type": "string",
      "format": "uri"
    },
    "methods": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "payment_instructions": {
      "type": "object",
      "required": [
        "methods",
        "wallet_id"
      ],
      "properties": {
        "methods": {
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "stablecoin",
              "bank_transfer"
            ]
          }
        },
        "wallet_id": {
          "type": "string",
          "maxLength": 200
        },
        "chain": {
          "type": "string",
          "maxLength": 40
        },
        "coin": {
          "type": "string",
          "maxLength": 10
        }
      }
    },
    "authentication": {
      "type": "string",
      "maxLength": 40
    },
    "capture": {
      "type": "string",
      "maxLength": 40
    },
    "save_method": {
      "type": "boolean"
    },
    "payer_id": {
      "type": "string",
      "maxLength": 200
    },
    "payer": {
      "type": "object"
    },
    "expires_at": {
      "type": "string",
      "format": "date-time"
    },
    "reference": {
      "type": "string",
      "maxLength": 200
    },
    "external_ref": {
      "type": "string",
      "maxLength": 200,
      "description": "The document this belongs to in your own system."
    },
    "external_kind": {
      "type": "string",
      "enum": [
        "invoice",
        "bill",
        "order",
        "booking",
        "other"
      ]
    },
    "metadata": {
      "type": "object",
      "maxProperties": 20,
      "additionalProperties": {
        "type": "string",
        "maxLength": 500
      },
      "description": "Up to 20 keys of at most 40 characters, with string values of at most 500."
    },
    "ui": {
      "type": "string",
      "enum": [
        "hosted",
        "embedded"
      ]
    },
    "dry_run": {
      "type": "boolean",
      "description": "Check the request and report what would happen, without doing it."
    }
  }
}
```

## Responses

- `200`: Success.
- `202`: requires_approval — Not an error: the operation is held for a person. The body names the approval.
- `400`: price_below_minimum — The price is below the smallest single payment for a method (`detail.method`, `detail.minimum`), or has a part of a cent. Set `credit_only`, raise the price, or drop the method.
- `401`: dpop_invalid — The token is bound to a key and the DPoP proof was missing, wrong for this request, or already used.
- `402`: payment_failed — The payer's bank or card refused. `detail.reason` says why in plain terms.
- `403`: agent_payment_over_max — The merchant asks for more than `max_amount`. Nothing was signed. `detail.asked_minor` is the lowest price asked, in US cents.
- `404`: not_found — No such object in this project — including one that belongs to somebody else.
- `409`: token_not_issued — A delegated payment token could not be issued ready to use, for instance because the payer would have to act. Nothing was sent to the merchant.
- `429`: too_many_waiters — This key already has as many requests waiting (`?wait=`) as it may. Let one finish, or read without wait.
- `500`: internal_error — Ours. Quote the `request_id` and we can find the call.
- `502`: platform_error — A provider failed. Safe to retry with the same Idempotency-Key.
- `503`: oauth_unavailable — The authorisation server's keys could not be read, so tokens cannot be checked. API keys still work.

## Example

```sh
curl -X POST 'https://api.skerry.xyz/checkout-sessions' \
  -H 'Authorization: Bearer $KEY' \
  -H 'Content-Type: application/json' \
  -d '"{ customer_id, amount | line_items, currency, success_url, cancel_url?, methods?, payment_instructions?: { methods: [stablecoin | bank_transfer], wallet_id, chain?, coin? }, authentication?, capture?, save_method?, payer_id? | payer?, expires_at?, reference?, external_ref?, external_kind?, metadata?, ui?, dry_run? }"'
```
