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

# Checkout from your server

> Create a checkout with your secret API key, with the product, plan, buyer email and your reference fixed, and confirm the order by the checkout's id.

# Checkout from your server

<Note>
  **Available on staging; production release pending.** `POST /v1/commerce/checkouts` and `GET /v1/commerce/checkouts/{id}` are not in production yet.
</Note>

Create the checkout from your server when you already know who is buying what and the buyer must not be able to change it: a contract signed in your own system, a renewal you priced, a seat you reserved. You send the product, the plan, the buyer's email and your reference with your **secret** API key; COPE answers with a `checkout_url` for you to send the buyer to.

Unlike a [prefilled checkout](./prefilled-checkout), which your page creates with the publishable key, a checkout created this way is the seller's:

* **The buyer cannot change the products, plans or quantities.** Changing a line from the checkout page is refused with `lines_locked`.
* **The buyer cannot change the email you set.** The checkout page shows it read-only. The other details you send stay the buyer's to correct, such as a postal code.
* **Your `metadata` and `external_reference` cannot be changed** from the checkout page, and arrive on the order's webhooks as `order.metadata`.
* **Redirect URLs must be registered.** A `success_url` or `cancel_url` that is not one of your registered redirect URLs is refused with `invalid_redirect_url` rather than ignored.

## Create the checkout

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://api.cope.com/v1/commerce/checkouts \
  -H "Authorization: Bearer $COPE_SECRET_KEY" \
  -H "Idempotency-Key: booking-4711-checkout" \
  -H "Content-Type: application/json" \
  -d '{
    "external_reference": "booking-4711",
    "currency": "EUR",
    "lines": [{ "product_id": "prod_...", "plan_id": "plan_...", "quantity": 1 }],
    "buyer_identity": { "email": "buyer@example.com", "country": "DE", "postal_code": "10115" },
    "metadata": { "crm_deal": "4711" },
    "checkout": { "success_url": "https://your-site.example/thank-you" }
  }'
```

The response is a `checkout` object. Send the buyer to its `checkout_url`. **It comes only with the create response**: the checkout keeps a digest of the link's token, so retrieving the checkout later does not return it. A repeat of the create with the same `Idempotency-Key` within 24 hours replays the stored response, link included, so its `status` may be out of date and its link may already have expired: a checkout expires 30 minutes after it was created.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "data": {
    "object": "checkout",
    "id": "chk_A1b2C3d4E5f6G7h8",
    "status": "open",
    "checkout_url": "https://app.cope.com/checkout/...",
    "external_reference": "booking-4711",
    "metadata": { "crm_deal": "4711" },
    "buyer_email_locked": true,
    "totals": { "currency": "EUR", "subtotal_minor_units": 4999, "tax_minor_units": 950, "total_minor_units": 5949 },
    "order": null
  }
}
```

* `Idempotency-Key` is required. A repeat with the same key answers with the same checkout.
* Ids are COPE's public ids. A line's `plan_id` is the plan's `plan_` id from `payment_plans[].uuid`; an integer is refused with `validation_error`.
* `metadata` is yours. `external_reference`, `intended_payment_method` and the keys COPE reserves for itself are refused inside it with `reserved_metadata_key`.
* A member the operation does not take is refused with `invalid_request` (400). A checkout created from your server does not take buyer consents: the buyer gives them on the checkout page.

## Confirm the order by the checkout's id

Store the `chk_` id. When the buyer has paid, `GET /v1/commerce/checkouts/{id}` names the order.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{ "data": { "object": "checkout", "id": "chk_A1b2C3d4E5f6G7h8", "status": "completed", "order": { "object": "order", "id": "ord_..." } } }
```

`status` reads `completed` whenever `order` is set. A checkout expires 30 minutes after you create it; create a new one for a buyer who comes back later.

Match the order in `payment.sale.succeeded` to that `order.id` before you fulfil, rather than matching on `external_reference`: a checkout link anyone can open can carry the same reference.

See the API reference for every member and error.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.