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

# Environments

> Sandbox vs Production, base URLs, and how to switch safely.

Waftpay provides two environments:

* **Sandbox** - a safe, isolated environment for development and QA.
* **Production** - live traffic and real money movement.

Functionality and payload shapes are **parity-aligned** between environments. Any differences are noted below.

***

## Base URLs

Use the correct host per environment when composing endpoints.

| Environment           | Base URL                 |
| --------------------- | ------------------------ |
| **Sandbox (dev)**     | `https://dev.waftpay.io` |
| **Production (prod)** | `https://waftpay.io`     |

> **Note:** All APIs are served through the Waftpay gateway. The only difference between environments is the host (`dev` vs `prod`); the service path (for example `/auth/api/v1/generate-token`) is identical in both.

### Service examples

**Authentication (Consumer credentials):**

* Sandbox: `https://dev.waftpay.io/auth/api/v1/generate-token`
* Production: `https://waftpay.io/auth/api/v1/generate-token`

**Payments / Payouts:**

* Sandbox: `https://dev.waftpay.io/payments/api/v1/payouts`
* Production: `https://waftpay.io/payments/api/v1/payouts`

***

## Switching environments

We recommend parameterizing the base URL and credentials.

```bash theme={null}
# .env (example)
WAFTPAY_BASE_URL=https://dev.waftpay.io
WAFTPAY_CONSUMER_KEY=...
WAFTPAY_CONSUMER_SECRET=...
WAFTPAY_PUBLIC_KEY_PATH=./keys/sandbox_public.pem
WAFTPAY_PRIVATE_KEY_PATH=./keys/sandbox_private.pem
```

```ts theme={null}
// config.ts
export const WAFTPAY = {
  baseUrl: process.env.WAFTPAY_BASE_URL ?? "https://dev.waftpay.io",
  consumerKey: process.env.WAFTPAY_CONSUMER_KEY!,
  consumerSecret: process.env.WAFTPAY_CONSUMER_SECRET!,
};
```

Switch to Production by setting:

```bash theme={null}
WAFTPAY_BASE_URL=https://waftpay.io
# ...and production credentials / keys
```

***

## Quick start: per‑environment calls

### 1) Get an access token

```bash theme={null}
# SANDBOX
curl -X POST \
  https://dev.waftpay.io/auth/api/v1/generate-token \
  -H 'Content-Type: application/json' \
  -d '{
    "consumer_key":"<sandbox-consumer-key>",
    "consumer_secret":"<sandbox-consumer-secret>"
  }'
```

```bash theme={null}
# PRODUCTION
curl -X POST \
  https://waftpay.io/auth/api/v1/generate-token \
  -H 'Content-Type: application/json' \
  -d '{
    "consumer_key":"<prod-consumer-key>",
    "consumer_secret":"<prod-consumer-secret>"
  }'
```

### 2) Create a payout

```bash theme={null}
# SANDBOX
curl --request POST \
  --url https://dev.waftpay.io/payments/api/v1/payouts \
  --header 'Authorization: Bearer <sandbox-access-token>' \
  --header 'Content-Type: application/json' \
  --header 'X-Custom-Signature: <signature>' \
  --data '{
  "transaction": {
    "reference": "TXN213687756272200",
    "amount": 1000,
    "currency": "KES",
    "description": "Test description",
    "service_code": "MPESAB2C",
    "timestamp": "2025-01-21T12:30:10Z"
  },
  "originator": {
    "msisdn": "254708374149",
    "channel": "USSD",
    "country": "KE"
  },
  "recipient": {
    "reference": "INVJMA02",
    "account": "254708374149"
  },
  "callback_url": "https://staging.example.com/waftpay/callbacks"
}'
```

```bash theme={null}
# PRODUCTION
curl --request POST \
  --url https://waftpay.io/payments/api/v1/payouts \
  --header 'Authorization: Bearer <prod-access-token>' \
  --header 'Content-Type: application/json' \
  --header 'X-Custom-Signature: <signature>' \
  --data '{
  "transaction": {
    "reference": "TXN213687756272201",
    "amount": 1000,
    "currency": "KES",
    "description": "Live payout",
    "service_code": "MPESAB2C",
    "timestamp": "2025-01-21T12:30:10Z"
  },
  "originator": {
    "msisdn": "2547XXXXXXXX",
    "channel": "USSD",
    "country": "KE"
  },
  "recipient": {
    "reference": "INVLIVE01",
    "account": "2547YYYYYYYY"
  },
  "callback_url": "https://merchant.example.com/waftpay/callbacks"
}'
```

***

## Credentials & keys

* Maintain **separate** consumer keys/secrets and signing keys per environment.
* Keep private keys **server‑side only** and rotate regularly.
* Enforce least privilege: ensure the Production client has access only to the services it needs.

> See **Authentication** and **Signing Requests** for how to generate and rotate RSA‑2048 PEM keys and how to compute `X-Custom-Signature`.

***

## Webhooks

* Use distinct webhook endpoints per environment, e.g.:
  * Sandbox → `https://staging.example.com/waftpay/callbacks`
  * Production → `https://merchant.example.com/waftpay/callbacks`
* Endpoints **must** be HTTPS and return a fast **2xx** to acknowledge.
* Verify the webhook signature using the same signing scheme used for requests.

***

## Behavioural differences

* **Limits & throughput:** Sandbox is throttled and may have lower throughput than Production.
* **Third‑party integrations:** In Sandbox, payouts and collections are **simulated** and will not move real funds.
* **Errors:** Error shapes and codes are identical across environments (see **Errors**).

***

## Best practices

* Treat Production credentials and keys as **secrets**; keep them out of client apps and repos.
* Log the **environment**, **request\_id**, and **extended error code** for every call.
* Use **idempotency** on POSTs and ensure `transaction.reference` is unique per attempt.
* Run end‑to‑end tests in Sandbox before promoting changes to Production.
* Monitor webhooks separately per environment and alert on delivery failures.

***

## See also

* **Authentication** - obtain a consumer-credentials token: [/api-reference/auth/auth-token](/api-reference/auth/auth-token)
* **Signing Requests** - compute and send `X-Custom-Signature`: [/api-reference/signatures/signature-generate](/api-reference/signatures/signature-generate)
* **Errors** - interpret extended error codes: [/errors](/errors)
