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

# Quickstart

> Authenticate, collect your first payment, and send your first payout.

This walkthrough takes you from credentials to a completed charge and payout in the sandbox. Every
request goes to `https://api.zerocash.tech`.

<Note>
  Use your **sandbox** keys throughout. Sandbox and production share the same base URL — the
  credentials decide which environment you are in. See [Environments](/guides/environments).
</Note>

## Step 1 — Generate a bearer token

Exchange your public key and API key for a token.

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.zerocash.tech/api/b2b/auth/generate-bearer-token \
    --header 'api-key: YOUR_API_KEY' \
    --header 'content-type: application/json' \
    --data '{"publicKey":"YOUR_PUBLIC_KEY"}'
  ```

  ```javascript Node.js theme={null}
  const auth = await fetch(
    "https://api.zerocash.tech/api/b2b/auth/generate-bearer-token",
    {
      method: "POST",
      headers: {
        "api-key": process.env.ZEROCASH_API_KEY,
        "content-type": "application/json",
      },
      body: JSON.stringify({ publicKey: process.env.ZEROCASH_PUBLIC_KEY }),
    }
  ).then((r) => r.json());

  const token = auth.token;
  ```
</CodeGroup>

```json Response theme={null}
{
  "success": true,
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.....",
  "expiresAt": 1752085041
}
```

Send this token as `Authorization: Bearer <token>` on every request that follows. It expires at
`expiresAt` (Unix seconds) — refresh against that value rather than assuming a fixed lifetime.

## Step 2 — Collect a payment

Charge a customer's mobile money wallet. For `KES` you only need the phone number; every other
currency also needs a `momoOperatorId` from the
[mobile money operators](/guides/mobile-money-operators) list.

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.zerocash.tech/api/b2b/fiat/deposit/momo \
    --header 'Authorization: Bearer YOUR_BEARER_TOKEN' \
    --header 'content-type: application/json' \
    --data '{
      "amount": 100,
      "currency": "KES",
      "externalReference": "order_12345",
      "phoneNumber": "254712345678"
    }'
  ```

  ```javascript Node.js theme={null}
  const charge = await fetch(
    "https://api.zerocash.tech/api/b2b/fiat/deposit/momo",
    {
      method: "POST",
      headers: {
        authorization: `Bearer ${token}`,
        "content-type": "application/json",
      },
      body: JSON.stringify({
        amount: 100,
        currency: "KES",
        externalReference: "order_12345",
        phoneNumber: "254712345678",
      }),
    }
  ).then((r) => r.json());
  ```
</CodeGroup>

```json Response theme={null}
{
  "success": true,
  "message": "Initiated request.",
  "transactionId": "123456789"
}
```

<Warning>
  This response means the request was **accepted**, not that money moved. The customer still has
  to approve the prompt. Do not fulfil the order yet.
</Warning>

`externalReference` is your own unique ID. Keep it unique per attempt — it is how you reconcile,
and how you avoid double-charging on a retry.

## Step 3 — Confirm the outcome

Money movement is asynchronous, so you confirm the result one of two ways.

<Tabs>
  <Tab title="Webhooks (recommended)">
    Configure a webhook URL in your dashboard and Zerocash pushes each status change to you.

    ```json transaction_updated theme={null}
    {
      "event": "transaction_updated",
      "data": {
        "transactionId": "BeOfXV1NVIcZlsSVeQAF",
        "status": "successful",
        "type": "deposit",
        "externalReference": "order_12345",
        "method": "momo",
        "thirdPartyReference": "TEQTEYRU"
      },
      "timestamp": "2024-10-03T16:33:14.600Z"
    }
    ```

    Always [verify the signature](/guides/webhooks/secrets) before trusting a payload.
  </Tab>

  <Tab title="Polling">
    Look the transaction up by `transactionId` or by your `externalReference`.

    ```bash theme={null}
    curl --request GET \
      --url https://api.zerocash.tech/api/b2b/transactions/order_12345 \
      --header 'Authorization: Bearer YOUR_BEARER_TOKEN'
    ```

    ```json Response theme={null}
    {
      "success": true,
      "data": {
        "transactionId": "lBK9bMny2gs4hLsG3XGq",
        "amount": 100,
        "type": "deposit",
        "currency": "KES",
        "chargeStatus": "successful",
        "status": "SUCCESSFUL",
        "method": "momo",
        "externalReference": "order_12345",
        "thirdPartyReference": "TFH174NFSJ"
      }
    }
    ```
  </Tab>
</Tabs>

Some charges come back with a `stepRequired` field before they reach a final status:

| `stepRequired` | What to do                                                                                                |
| :------------- | :-------------------------------------------------------------------------------------------------------- |
| `otp`          | Collect the code from the customer and submit it to [Validate OTP](/api-reference/endpoint/validate-otp). |
| `redirect`     | Send the customer to the returned `redirectUrl` to authorise the payment.                                 |

Only release goods or credit an account once the status is `successful`.

## Step 4 — Send a payout

Payouts use a single endpoint for every destination. The `destination` field and the shape of
`payoutMethod` determine where the money goes.

<CodeGroup>
  ```bash Mobile money theme={null}
  curl --request POST \
    --url https://api.zerocash.tech/api/b2b/fiat/payout \
    --header 'Authorization: Bearer YOUR_BEARER_TOKEN' \
    --header 'content-type: application/json' \
    --data '{
      "amount": 100,
      "currency": "KES",
      "country": "KE",
      "externalReference": "payout_12345",
      "destination": "MoMo",
      "payoutMethod": {
        "accountName": "Test User",
        "accountNumber": "254712345678"
      }
    }'
  ```

  ```bash Bank account theme={null}
  curl --request POST \
    --url https://api.zerocash.tech/api/b2b/fiat/payout \
    --header 'Authorization: Bearer YOUR_BEARER_TOKEN' \
    --header 'content-type: application/json' \
    --data '{
      "amount": 100,
      "currency": "KES",
      "country": "KE",
      "externalReference": "payout_12346",
      "destination": "Bank Account",
      "payoutMethod": {
        "accountName": "Test User",
        "accountNumber": "1234567890",
        "code": "07"
      }
    }'
  ```
</CodeGroup>

```json Response theme={null}
{
  "success": true,
  "message": "Withdrawal Request Accepted for Processing.",
  "transactionId": "mIt5ycmF3YCqaOQp6Ljz"
}
```

As with charges, this is an acknowledgement. Wait for the `transaction_updated` webhook — or poll
the transaction — before you treat the payout as delivered.

<Tip>
  In sandbox, account number `254712345678` always succeeds and `254787654321` always fails, so you
  can exercise both branches. Full list in [Testing payouts](/guides/testing/payouts).
</Tip>

## Where to next

<CardGroup cols={2}>
  <Card title="Choose a charge method" icon="arrow-down-to-line" href="/guides/collections/overview">
    Compare mobile money, bank transfer, card, and OPay.
  </Card>

  <Card title="Payouts in depth" icon="arrow-up-from-line" href="/guides/payouts/payouts">
    Every destination type, cross-currency debits, and saved beneficiaries.
  </Card>

  <Card title="Set up webhooks" icon="bell" href="/guides/webhooks/getting-started">
    Receive status changes instead of polling.
  </Card>

  <Card title="API reference" icon="code" href="/api-reference/introduction">
    Full schemas and an interactive playground for all 32 endpoints.
  </Card>
</CardGroup>
