# Programmatic merchant API

Server-to-server flows for **collections** (STK push) and **disbursements** (B2C). Authenticate with your merchant **API key** and **API secret** only on the two OAuth-style token endpoints; all other calls use a short-lived `Authorization: Bearer` token with the matching scope.

### Endpoint summary

| Method | Path | Purpose |
| --- | --- | --- |
| POST | `/v1/oauth/collections/token` | Issue Bearer token (collections scope) |
| POST | `/v1/oauth/disbursements/token` | Issue Bearer token (disbursements scope) |
| POST | `/v1/collect` | Initiate collection (collections token) |
| POST | `/v1/disburse` | Initiate disbursement (disbursements token) |
| GET | `/v1/collect/transactions/:transactionId` | Collection status |
| GET | `/v1/disburse/transactions/:transactionId` | Disbursement status |

Production URLs: API `https://core.swarmbyte.com`, merchant hub `https://pay.swarmbyte.com`, and this documentation site `https://docs.swarmbyte.com`.

New to the API? Read [Integration guide](https://docs.swarmbyte.com/integration.md) next, then open [Field reference](https://docs.swarmbyte.com/field-reference.md) for header and JSON definitions. Shared error shape, validation, limits, and error handling: [Errors overview](https://docs.swarmbyte.com/errors-overview.md). Detailed HTTP tables for each route are on the matching tab ([Token (collections)](https://docs.swarmbyte.com/oauth-collections-token.md), [Token (disbursements)](https://docs.swarmbyte.com/oauth-disbursements-token.md), [Collect](https://docs.swarmbyte.com/collect.md), [Collection status](https://docs.swarmbyte.com/collect-status.md), [Disburse](https://docs.swarmbyte.com/disburse.md), [Disbursement status](https://docs.swarmbyte.com/disburse-status.md)).

## Credentials

Use your merchant **API Key** as `client_id` and **API Secret** as `client_secret` (from the dashboard). The same pair works for both token endpoints — the URL path selects **collections** or **disbursements** scope.

Programmatic `POST /v1/disburse` also requires **API disbursements** to be enabled on your account and a disbursement **PIN** configured in the dashboard.

## Scopes

- **collections** — use only for `POST /v1/collect` and `GET /v1/collect/transactions/:transactionId`.
- **disbursements** — use only for `POST /v1/disburse` and `GET /v1/disburse/transactions/:transactionId`.
- Calling an endpoint with the wrong scope returns **403 Forbidden** with a message that the route requires the other scope.

## IP allowlist

Token exchange and every Bearer request must come from an IP address on your merchant **programmatic allowlist** (configured in the merchant dashboard, max three entries). If the allowlist is empty, requests are rejected with **403**. Responses may include a `clientIp` field to aid debugging.

## Idempotency

`POST /v1/collect` and `POST /v1/disburse` require the `X-Idempotency-Key` header (non-empty; max **200** characters). A duplicate request with the same key can receive **409 Conflict** if the first call is still processing and the duplicate times out while waiting; once the first call has finished, the same key typically **replays** the stored outcome (**202**). See [Field reference](https://docs.swarmbyte.com/field-reference.md) for full semantics.

## Amounts

Minimum amount per collect/disburse: **500 UGX**. A maximum per transaction is also enforced server-side.

## HTTP status codes (typical)

| Code | Meaning |
| --- | --- |
| 200 | Token issued; GET transaction succeeded |
| 202 | Collect or disburse accepted for processing |
| 400 | Validation, missing idempotency key, invalid webhook URL, amount bounds |
| 401 | Invalid credentials or Bearer token; merchant not eligible (KYC, suspended, etc.) |
| 403 | Wrong scope; IP not allowed; API disbursements disabled; wrong transaction type for GET path |
| 404 | Transaction not found |
| 409 | Idempotency: same key still in-flight (wait timeout); retries after completion replay with 202 |
| 429 | Rate limited |
| 503 | Service temporarily unavailable — retry later |

Error responses use JSON with `statusCode`, `message`, `error`, and usually `requestId` for support.

## Security (integrators)

- Keep **API secrets**, Bearer tokens, and disbursement **PINs** on the server only — never in mobile apps, frontends, or public repos.
- Use **HTTPS** for every call to SwarmByte and for your `webhookUrl`.
- Rotate API credentials from the merchant dashboard if they may have been exposed.
- Log request metadata (transaction id, HTTP status) — avoid logging full PINs, secrets, or Bearer tokens.

Source: https://docs.swarmbyte.com/
