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

# Quickstart

> Authenticate, collect a payment and send a payout in sandbox.

This guide takes you from sandbox keys to a completed collection and payout. It takes about ten minutes.

## Before you start

You need a Tanda account with sandbox access. Sign in to the [dashboard](https://app.tandapay.io) and open **Developers → API keys** to find your sandbox **public key** and **API key**.

> [!WARNING]
>
> Your API key is a secret. Keep it on your server, in an environment variable or secrets manager. Never put it in a browser, mobile app or repository.

**1. Generate a bearer token**

Send your API key in the `api-key` header and your public key in the body.

```bash cURL theme={null}
curl -X POST https://api.tandapay.io/api/b2b/auth/generate-bearer-token \
  -H "api-key: $TANDA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "publicKey": "'"$TANDA_PUBLIC_KEY"'" }'
```

```javascript Node.js theme={null}
const res = await fetch("https://api.tandapay.io/api/b2b/auth/generate-bearer-token", {
  method: "POST",
  headers: { "api-key": process.env.TANDA_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({ publicKey: process.env.TANDA_PUBLIC_KEY }),
});
const { token } = await res.json();
```

```python Python theme={null}
import os, requests

res = requests.post(
    "https://api.tandapay.io/api/b2b/auth/generate-bearer-token",
    headers={"api-key": os.environ["TANDA_API_KEY"]},
    json={"publicKey": os.environ["TANDA_PUBLIC_KEY"]},
)
token = res.json()["token"]
```

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

The token lasts one hour. Send it as `Authorization: Bearer <token>` on every other request.

**2. Check your account**

Confirm the token works and see your sandbox balance and webhook URLs.

```bash theme={null}
curl https://api.tandapay.io/api/b2b/users \
  -H "Authorization: Bearer $TOKEN"
```

**3. Collect a payment**

Send an M-PESA prompt to a sandbox test number. `254712345678` always succeeds in sandbox.

```bash cURL theme={null}
curl -X POST https://api.tandapay.io/api/b2b/fiat/deposit/momo \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1500,
    "currency": "KES",
    "phoneNumber": "254712345678",
    "externalReference": "quickstart-charge-001"
  }'
```

```javascript Node.js theme={null}
const charge = await fetch("https://api.tandapay.io/api/b2b/fiat/deposit/momo", {
  method: "POST",
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    amount: 1500,
    currency: "KES",
    phoneNumber: "254712345678",
    externalReference: "quickstart-charge-001",
  }),
}).then((r) => r.json());
```

```python Python theme={null}
charge = requests.post(
    "https://api.tandapay.io/api/b2b/fiat/deposit/momo",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "amount": 1500,
        "currency": "KES",
        "phoneNumber": "254712345678",
        "externalReference": "quickstart-charge-001",
    },
).json()
```

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

> [!TIP]
>
> Want Tanda to host the payment page instead? [Create a checkout session](https://api.tandapay.io/guides/collections/checkout.md) and redirect the customer to the link it returns.

**4. Confirm the outcome**

Fetch the transaction by its `transactionId` or your `externalReference`. In production you'd wait for a [webhook](https://api.tandapay.io/guides/webhooks/overview.md) instead of polling.

```bash theme={null}
curl https://api.tandapay.io/api/b2b/transactions/quickstart-charge-001 \
  -H "Authorization: Bearer $TOKEN"
```

Fulfil only when `chargeStatus` is `successful`.

**5. Send a payout**

Pay out to an M-PESA wallet. In sandbox, `254712345678` succeeds and `254787654321` fails.

```bash theme={null}
curl -X POST https://api.tandapay.io/api/b2b/fiat/payout \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1000,
    "currency": "KES",
    "country": "KE",
    "destination": "MoMo",
    "externalReference": "quickstart-payout-001",
    "payoutMethod": {
      "accountName": "Grace Achieng",
      "accountNumber": "254712345678",
      "code": "mpesa"
    }
  }'
```

The final status arrives as a `payout_updated` webhook.

## Next steps

> **[Set up webhooks](https://api.tandapay.io/guides/webhooks/overview.md)**
>
> Receive outcomes in real time instead of polling.

> **[Test every outcome](https://api.tandapay.io/guides/testing.md)**
>
> Sandbox values for success, failure and every customer step.


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