# Read browser checkout state

Possession of the session ID addresses this customer checkout. These endpoints support the hosted page and SDK; prefer those clients over reimplementing provider-specific actions.

## Endpoint

GET https://api.veyqo.org/checkout/v1/sessions/{id}

The resource ID addresses this customer checkout. Do not expose it unnecessarily. This endpoint supports the hosted page and checkout script.

## Path and query parameters

| Parameter | Location | Required | Description |
| --- | --- | --- | --- |
| id | path | Yes | Use the ID returned when this resource was created. |

## Example request

Examples use illustrative IDs and provider URLs. Replace path variables with IDs returned by your own requests. Never paste a live secret into client code or a public tool.

### cURL

```bash
curl --request GET "https://api.veyqo.org/checkout/v1/sessions/$CHECKOUT_SESSION_ID" \
  --header "Accept: application/json"
```

### Node.js

```javascript
// Server-side Node.js 18+. Save operation.idempotencyKey before a write.
const response = await fetch(`https://api.veyqo.org/checkout/v1/sessions/${encodeURIComponent(process.env.CHECKOUT_SESSION_ID)}`, {
  method: 'GET',
  headers: {
  "Accept": "application/json"
},
});
const result = await response.json();
if (!response.ok || !result.success) {
  console.error(response.status, result.error?.code, response.headers.get('X-Request-Id'));
  throw new Error(result.error?.message ?? 'Veyqo request failed');
}
console.log(result.data);
```

### PHP

```php
<?php
// Server-side PHP with the cURL extension. Persist $operationIdempotencyKey.
$curl = curl_init('https://api.veyqo.org/checkout/v1/sessions/'.rawurlencode(getenv('CHECKOUT_SESSION_ID')).'');
curl_setopt_array($curl, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTPHEADER => [
    'Accept: application/json'
  ],
]);
$body = curl_exec($curl);
if ($body === false) throw new RuntimeException(curl_error($curl));
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
if ($status >= 400 || !($result['success'] ?? false)) {
  throw new RuntimeException($result['error']['code'] ?? 'Veyqo request failed');
}
print_r($result['data']);
```

### Python

```python
# pip install requests; run on your server.
import os, requests
from urllib.parse import quote

response = requests.request('GET', f'https://api.veyqo.org/checkout/v1/sessions/{quote(os.environ["CHECKOUT_SESSION_ID"], safe="")}',
    headers={
  "Accept": "application/json"
},
    timeout=30)
result = response.json()
if not response.ok or not result.get('success'):
    raise RuntimeError(f"{response.status_code} {result.get('error')} request_id={response.headers.get('X-Request-Id')}")
print(result['data'])
```

## Successful response · 200

HTTP success means the request was accepted. A pending payment or refund is not completed merely because the response is 200 or 201.

```json
{
  "success": true,
  "data": {
    "id": "cs_01M6EB66SC61Q3RQYAN0693DGM",
    "object": "checkout_session",
    "url": "https://veyqo.org/pay/cs_01M6EB66SC61Q3RQYAN0693DGM",
    "status": "open",
    "source": "api",
    "provider": {
      "slug": "paystack",
      "name": "Paystack"
    },
    "amount": 50000,
    "currency": "NGN",
    "reference": "ORDER-1001",
    "description": "Order 1001",
    "customer_email": "customer@example.com",
    "payment": null,
    "success_url": "https://shop.example.com/thanks",
    "cancel_url": "https://shop.example.com/cart",
    "expires_at": "2026-11-02T13:00:00+00:00",
    "completed_at": null,
    "created_at": "2026-11-02T12:00:00+00:00",
    "merchant": {
      "name": "Example Store"
    },
    "sandbox": true,
    "needs_email": false,
    "methods": [
      {
        "id": "card"
      },
      {
        "id": "bank_transfer"
      },
      {
        "id": "ussd",
        "banks": [
          {
            "code": "737",
            "name": "GTBank"
          },
          {
            "code": "919",
            "name": "UBA"
          },
          {
            "code": "822",
            "name": "Sterling Bank"
          },
          {
            "code": "966",
            "name": "Zenith Bank"
          }
        ]
      }
    ],
    "next_action": null
  }
}
```

## Response fields

| Field in data | Type | Presence | Description |
| --- | --- | --- | --- |
| id | string | Required | Checkout session ID (cs_ prefix). |
| object | "checkout_session" | Required | See the JSON example. |
| url | string | Required | Hosted Veyqo URL; redirect here or open this session using VeyqoCheckout. Format: uri. |
| status | string | Required | Values: open, completed, expired. |
| source | string | Required | Values: api, browser, link. |
| provider | object \| null | Required | Available provider identity, never secret credentials. |
| provider.slug | string | Optional | See the JSON example. |
| provider.name | string | Optional | See the JSON example. |
| amount | integer | Required | Server-defined amount in minor units. |
| currency | string | Required | Three-letter currency. |
| reference | string \| null | Required | Your order reference, when supplied. |
| description | string \| null | Required | Checkout description. |
| customer_email | string \| null | Required | Customer email if already supplied. |
| payment | object \| null | Required | Current payment attempt, if any. A session can have multiple attempts over time. |
| success_url | string \| null | Required | Configured return URL. A redirect is not proof of payment. |
| cancel_url | string \| null | Required | Configured cancellation URL. |
| expires_at | string | Required | Session expiry time. Format: date-time. |
| completed_at | string \| null | Required | ISO 8601 timestamp. Format: date-time. |
| created_at | string \| null | Required | ISO 8601 timestamp. Format: date-time. |
| merchant | object | Required | See the JSON example. |
| merchant.name | string | Required | See the JSON example. |
| sandbox | boolean | Required | See the JSON example. |
| needs_email | boolean | Required | See the JSON example. |
| methods | array | Required | Currency-dependent method descriptions. Use the hosted page/SDK instead of hard-coding this provider-specific payload. |
| next_action | object \| null | Required | Provider-specific action for the hosted checkout: bank details, USSD instructions, OTP or secure card form. May change per method. |

## Errors and recovery

| Code | HTTP | Recovery | Retry policy |
| --- | --- | --- | --- |
| VALIDATION_FAILED | 422 | Read error.details when present, correct the named fields and retry only after correction. Validation messages may describe state/capability errors without field details. | No automatic retry. |
| RESOURCE_NOT_FOUND | 404 | Check the ID, project and environment. Do not guess another project’s IDs. An inactive payment link is also not-found. | No blind retry. |
| RATE_LIMIT_EXCEEDED | 429 | Honor Retry-After, use bounded exponential backoff with jitter, and reduce concurrent requests. Read X-RateLimit headers. | Yes, after Retry-After; preserve write idempotency. |
| PROVIDER_UNAVAILABLE | 503 | Check the existing payment and verify its state before starting another attempt. Retry safe reads with backoff; preserve operation identity for retried writes. | Conditional: reconcile unknown outcomes first. |
| INTERNAL_ERROR | 500 | Record X-Request-Id, timestamp and sanitized request context. Reconcile unknown payment outcomes before retrying a write; contact support if it persists. | Safe reads: bounded backoff. Writes: reconcile first. |

- [Complete error catalogue](https://veyqo.org/docs/errors): Every Veyqo error code, including which surface emits it and how to recover.
