# Session reference

> Complete field reference for the VINR Checkout session API — request, response, statuses, and errors.

Every field accepted by `POST /checkout/session`. Only `amount`, `currency`, `successUrl`, and `cancelUrl` are required. The rest unlock cart UI, promo codes, delivery, and branding.

## Endpoint summary

|                    |                                                                   |
| ------------------ | ----------------------------------------------------------------- |
| **Method**         | `POST`                                                            |
| **Path**           | `/checkout/session`                                               |
| **Base URL**       | `https://api.vinr.com`                                            |
| **Authentication** | `X-Api-Key: <merchant-api-key>` header                            |
| **Content-Type**   | `application/json`                                                |
| **Idempotency**    | Pass `Idempotency-Key: <uuid>` to safely retry on network failure |

## Top-level fields

| Field                 | Type         | Description                                                                                                  | Default |
| --------------------- | ------------ | ------------------------------------------------------------------------------------------------------------ | ------- |
| `amount`              | `integer`    | Payment amount in minor units (e.g. 5000 = €50.00).                                                          | `—`     |
| `currency`            | `string`     | ISO 4217 three-letter currency code, e.g. \\                                                                 | `—`     |
| `successUrl`          | `string`     | HTTPS URL VINR redirects the customer to after a successful payment. Receives ?sessionId= query param.       | `—`     |
| `cancelUrl`           | `string`     | HTTPS URL VINR redirects the customer to when they click Cancel.                                             | `—`     |
| `customer`            | `Customer`   | Pre-fill customer details. Omit entirely for guest checkout.                                                 | `—`     |
| `cartItems`           | `CartItem[]` | Line items rendered in the checkout UI. Does not affect the charged amount — that is controlled by amount.   | `—`     |
| `supportedCurrencies` | `string[]`   | Array of ISO 4217 codes the customer can switch to. Defaults to \[currency] if omitted.                      | `—`     |
| `configId`            | `string`     | Branding / configuration preset defined in the dashboard.                                                    | `\`     |
| `metadata`            | `Metadata`   | Controls UI behaviors: mode, shipping address collection, promo codes, delivery options. See Metadata below. | `—`     |

## Customer object

| Field        | Type     | Description                                           | Default |
| ------------ | -------- | ----------------------------------------------------- | ------- |
| `customerId` | `string` | Your internal customer ID. Stored for reconciliation. | `—`     |
| `email`      | `string` | Pre-fills the email field on the checkout page.       | `—`     |
| `name`       | `string` | Customer full name.                                   | `—`     |
| `phone`      | `string` | E.164 format phone number.                            | `—`     |

## Cart item

| Field         | Type      | Description                                              | Default |
| ------------- | --------- | -------------------------------------------------------- | ------- |
| `id`          | `string`  | Your internal product / SKU identifier.                  | `—`     |
| `name`        | `string`  | Product name shown in the cart UI.                       | `—`     |
| `description` | `string`  | Short product description shown below the name.          | `—`     |
| `price`       | `integer` | Unit price in minor units (e.g. 2500 = €25.00).          | `—`     |
| `quantity`    | `integer` | Number of units. Must be >= 1.                           | `—`     |
| `image`       | `string`  | Absolute HTTPS URL for the product thumbnail.            | `—`     |
| `maxQuantity` | `integer` | Maximum quantity the customer can select in the cart UI. | `—`     |

## Metadata

The `metadata` object controls optional checkout behaviors. All fields are optional.

#### Mode and branding

| Field          | Type                          | Description                                                            |
| -------------- | ----------------------------- | ---------------------------------------------------------------------- |
| `mode`         | `"payment" \| "subscription"` | Displays payment or subscription UI language. Defaults to `"payment"`. |
| `merchantName` | string                        | Overrides the merchant display name shown on the checkout page.        |

#### Shipping address

| Field                     | Type                  | Description                                                   |
| ------------------------- | --------------------- | ------------------------------------------------------------- |
| `shippingAddressHandling` | `"Collect" \| "Skip"` | `"Collect"` shows a shipping address form. `"Skip"` omits it. |

#### Promo codes

Each entry in `availableCodes`:

| Field          | Type                      | Description                                           |
| -------------- | ------------------------- | ----------------------------------------------------- |
| `code`         | string                    | The code the customer enters, e.g. `"SAVE20"`.        |
| `discount`     | number                    | Discount value. Interpret with `discountType`.        |
| `discountType` | `"percentage" \| "fixed"` | `"percentage"`: 0–100. `"fixed"`: minor units.        |
| `description`  | string                    | Human-readable label shown after the code is applied. |

#### Delivery

Each `ShippingMethod`:

| Field               | Type    | Description                          |
| ------------------- | ------- | ------------------------------------ |
| `id`                | string  | Your internal method identifier.     |
| `name`              | string  | Display name, e.g. `"UPS Standard"`. |
| `price`             | integer | Cost in minor units.                 |
| `currency`          | string  | ISO 4217 code for the shipping cost. |
| `estimatedDays.min` | integer | Minimum estimated delivery days.     |
| `estimatedDays.max` | integer | Maximum estimated delivery days.     |

## Full example payload

```json
{
  "amount": 5000,
  "currency": "EUR",
  "successUrl": "https://yoursite.com/order/success",
  "cancelUrl": "https://yoursite.com/cart",
  "customer": {
    "customerId": "cust_abc123",
    "email": "jane@example.com",
    "name": "Jane Smith",
    "phone": "+12125551234"
  },
  "cartItems": [
    {
      "id": "item_001",
      "name": "Wireless headphones",
      "description": "Over-ear, noise cancelling",
      "price": 5000,
      "quantity": 1,
      "image": "https://yoursite.com/images/headphones.jpg",
      "maxQuantity": 5
    }
  ],
  "supportedCurrencies": ["EUR", "USD", "GBP"],
  "configId": "default-config",
  "metadata": {
    "mode": "payment",
    "merchantName": "Demo Store",
    "shippingAddressHandling": "Collect",
    "promoCode": {
      "enabled": true,
      "availableCodes": [
        {
          "code": "SAVE20",
          "discount": 20,
          "discountType": "percentage",
          "description": "20% off your order"
        }
      ]
    },
    "delivery": {
      "enabled": true,
      "options": {
        "shipping": {
          "methods": [
            {
              "id": "ups_standard",
              "name": "UPS Standard",
              "price": 599,
              "currency": "EUR",
              "estimatedDays": { "min": 3, "max": 5 }
            },
            {
              "id": "ups_express",
              "name": "UPS Express",
              "price": 1299,
              "currency": "EUR",
              "estimatedDays": { "min": 1, "max": 2 }
            }
          ]
        },
        "pickup": {
          "locations": [
            { "id": "loc_berlin_mitte", "name": "Berlin Mitte Store" }
          ]
        }
      }
    }
  }
}
```

## Response object

The response from `POST /checkout/session`:

| Field       | Type         | Description                                                      | Default |
| ----------- | ------------ | ---------------------------------------------------------------- | ------- |
| `id`        | `string`     | Session ID. Also referred to as sessionId elsewhere in the docs. | `—`     |
| `accountId` | `string`     | Your VINR merchant account ID.                                   | `—`     |
| `amount`    | `integer`    | Confirmed amount in minor units.                                 | `—`     |
| `currency`  | `string`     | Confirmed currency.                                              | `—`     |
| `status`    | `string`     | Always \\                                                        | `\`     |
| `customer`  | `Customer`   | Echo of the customer object you passed in.                       | `—`     |
| `cartItems` | `CartItem[]` | Echo of the cart items you passed in.                            | `—`     |
| `metadata`  | `Metadata`   | Echo of the metadata object you passed in.                       | `—`     |

## Verify a session result

Use this endpoint after the customer returns to `successUrl` to confirm the payment status before fulfilling an order.

**`GET /checkout/session/{sessionId}/result`** — same `X-Api-Key` header.

```ts
interface SessionResult {
  sessionId: string;
  status:
    | 'pending'
    | 'authentication_required'
    | 'completed'
    | 'failed'
    | 'canceled'
    | 'expired';
  amount: number;
  currency: string;
  customer?: {
    customerId?: string;
    email?: string;
    name?: string;
  };
}

async function verifySession(sessionId: string): Promise<SessionResult> {
  const res = await fetch(
    `${process.env.INTENT_API_URL}/checkout/session/${sessionId}/result`,
    { headers: { 'X-Api-Key': process.env.VINR_API_KEY! } }
  );
  if (!res.ok) throw new Error(`Unexpected status ${res.status}`);
  return res.json();
}

const result = await verifySession(sessionId);

if (result.status === 'completed') {
  await fulfillOrder(result);
} else if (result.status === 'failed') {
  await notifyCustomerOfFailure(result);
} else if (result.status === 'expired') {
  await redirectToNewSession();
} else if (result.status === 'canceled') {
  await redirectToCart();
} else if (result.status === 'authentication_required') {
  // 3DS is still in progress — poll again shortly or wait for the webhook
}
```

## Status reference

| Status                    | Meaning                                               | Recommended action                               |
| ------------------------- | ----------------------------------------------------- | ------------------------------------------------ |
| `pending`                 | Session created; customer has not completed payment.  | Wait or poll.                                    |
| `authentication_required` | 3DS challenge in progress.                            | Poll until status changes.                       |
| `completed`               | Payment captured successfully.                        | Fulfill the order.                               |
| `failed`                  | Payment declined or error during processing.          | Prompt the customer to retry with a new session. |
| `canceled`                | Customer clicked Cancel on the hosted page.           | Return the customer to their cart.               |
| `expired`                 | Session was not completed within the 5-minute window. | Create a new session.                            |

## Errors

| HTTP status | Meaning                                                             |
| ----------- | ------------------------------------------------------------------- |
| `400`       | Invalid request parameters — check field types and required fields. |
| `401`       | Missing or invalid `X-Api-Key`.                                     |
| `404`       | Session ID not found.                                               |
| `410`       | Session has expired. Create a new session.                          |
| `429`       | Rate limit exceeded — back off and retry with exponential delay.    |
