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

# API playground

> Try Zennopay endpoints live. Requests are sent against the sandbox server with your credentials.

Use the interactive playground below to exercise the Zennopay Partner API
against the sandbox environment. Every endpoint defined in
[`openapi.json`](https://github.com/Zennopay/zennopay-docs/blob/main/openapi.json)
is callable here — request bodies are validated client-side against the
schema before they're sent.

<Note>
  The playground talks to `https://api.sandbox.zennopay.com`. Use a
  **sandbox** HMAC key (`{partner}_sandbox_*`) — production keys are
  rejected by the sandbox host. The legacy `api.sandbox.zennopay.in` host is
  still served if your client is pinned to it.
</Note>

## What you'll need

* A sandbox HMAC key (`X-Zennopay-Key-Id`) and shared secret. Compute the
  signature with the canonical-request recipe from
  [Authentication](/authentication).
* For session-token endpoints (`GET /v1/payment_intents/{intent_id}` and
  `POST /v1/payment_intents/{intent_id}/confirm`), the `session_token` returned
  by a `POST /v1/payment_intents` call — send it as `Authorization: Bearer`.
  These are the calls the SDK normally makes; you rarely call them by hand.

## Endpoints

The playground is generated from [`/openapi.json`](/openapi.json) and groups
endpoints by tag:

* **Payment Intents** — `POST /v1/payment_intents`,
  `POST /v1/payment_intents/{intent_id}/session`,
  `POST /v1/payment_intents/{intent_id}/receipt_token`,
  `GET /v1/payment_intents/{intent_id}`,
  `POST /v1/payment_intents/{intent_id}/confirm`,
  `POST /v1/payment_intents/{intent_id}/cancel`

<Card title="Open the OpenAPI spec" icon="code" href="/openapi.json">
  Raw OpenAPI 3.1 document. Drop this into Postman, Insomnia, or your own
  codegen if you'd rather build a client locally.
</Card>

## Tips for first-time use

<AccordionGroup>
  <Accordion title="My HMAC request returns 401">
    The most common causes, in order:

    1. **Clock skew.** `X-Zennopay-Timestamp` must be within ±5 minutes
       of server time. NTP-sync your machine.
    2. **Body hash mismatch.** The canonical request hashes the *exact
       bytes* of the request body. Don't pretty-print or re-serialize
       between signing and sending.
    3. **Source IP not allowlisted.** The sandbox allowlist is configured
       per partner in the console.
  </Accordion>

  <Accordion title="My session-token call returns 401">
    In the default flow the session token is Zennopay-minted, so the usual
    causes are:

    * **Expired.** `session_expires_at` has passed. Create a fresh intent (or
      re-mint via `POST /v1/payment_intents/{intent_id}/session`) and use the
      new `session_token`.
    * **Wrong intent.** A token issued for intent A can't call intent B — the
      path `{intent_id}` must match the intent the token was minted for.
    * **Already consumed.** The confirming call is single-use; re-mint via
      `POST /v1/payment_intents/{intent_id}/session` if you need another.
  </Accordion>

  <Accordion title="My nonce keeps getting rejected">
    Each `X-Zennopay-Nonce` is single-use within a 10-minute window.
    Generate a fresh random 32-byte hex string for every request — never
    hardcode or reuse one.
  </Accordion>
</AccordionGroup>
