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

# Customers setup and configuration

> Credentials, environments, limits, webhooks, and the prerequisites the service enforces before it accepts a call.

## Credentials

Every customer operation is authenticated with an API key and nothing else. Session credentials are rejected: these routes are API-key only.

```http theme={null}
Authorization: Bearer sk_test_your_key_here
```

Keys are environment-bound. A `sk_test_…` key against the live host fails with `401 INVALID_API_KEY`, and so does the reverse — the failure is deliberately indistinguishable from an invalid key.

<Warning>
  API-key **scopes** are stored when a key is issued but are not enforced on the Business API today. Do not design a permission model that depends on scoping a key to customers only. This is an open item in `CONTRACT-DECISIONS.md`.
</Warning>

## Prerequisites the service checks

Two checks run before any customer work happens, in this order:

1. **The client exists.** If the key authenticates but its business has been removed, you get `404 client_not_found`.
2. **The client is a business.** Customer management is a business-client feature; anything else gets `409 client_not_a_business`.

There is no feature flag, tier gate, or product entitlement on customers. If your key works and your client is a business, all five operations are available.

## Environments

Sandbox and live are separate deployments with separate databases. A customer created in sandbox does not exist in live, and identifiers do not carry across.

| | Sandbox | Live |
| - | - | - |
| Key prefix | `sk_test_` | `sk_live_` |
| Webhook `endpoint` config | Configured independently | Configured independently |
| Customer data | Synthetic only | Real personal data |

<Warning>
  Never copy real identity numbers, real phone numbers, or real addresses into sandbox. Use clearly synthetic values, as every example in these pages does.
</Warning>

## Rate limits

Limits are per 60-second window and are counted **twice** for each request — once against your business, once against the individual key. Both must pass.

| Operation | Requests per minute |
| - | -: |
| `GET /v1/customers`, `GET /v1/customers/{customerId}` | 600 |
| `POST`, `PATCH`, `DELETE` | 120 |

Two further limits apply to every authenticated request regardless of route: 300 per minute per source IP, and 1,200 per minute per credential.

Exceeding any of them returns `429` with `retryAfterSeconds` in the body. There is no `Retry-After` header yet — read the body. See [rate limits](/guides/rate-limits) for backoff guidance.

Bulk import arithmetic follows directly: at 120 writes per minute, ten thousand customers takes about 83 minutes at a steady rate. Pace the job rather than absorbing `429`s.

## Webhooks

Customers emit two events, both carrying the complete customer object as their `data`:

| Event | Trigger |
| - | - |
| `customer.created` | `POST /v1/customers` succeeded |
| `customer.updated` | `PATCH /v1/customers/{customerId}` succeeded |

Archiving emits nothing.

Verification outcomes arrive as `customer.kyc.approved`, `customer.kyc.rejected` and `customer.kyc.suspended`, each carrying the customer object plus a `kyc` object. They follow the verification for as long as it exists, so the same customer can send more than one. See [Identity and verification](/services/customers/identity-and-verification).

Three things to get right in the receiver:

1. **Deduplicate on the `Sakawave-Webhook-Id` header.** The body has only `event` and `data`; there is no ID inside it.
2. **The event payload is a snapshot, not a delta.** It tells you the customer's state at that moment, not what changed. If you need the diff, compare against your own copy.
3. **Do not treat the event as the source of truth.** Delivery is a single attempt with manual resend and no automatic retry. Reconcile by listing customers.

See [verify signatures](/webhooks/verify-signatures) for complete handlers.

## Request identifiers

Send `X-Request-ID` on every call. It comes back on the response and is the fastest way for support to find your request. If you omit it, or send something malformed, Sakawave generates one.

## Configuration checklist

* [ ] Sandbox and live keys stored in a secrets manager, never in source control
* [ ] Base URL configured per environment, never hardcoded per call site
* [ ] `externalReference` chosen from a stable identifier in your own system
* [ ] Write throughput paced under 120 per minute
* [ ] `X-Request-ID` set from your own trace or correlation ID
* [ ] Webhook endpoint configured separately in each environment, deduplicating on the header ID
* [ ] Error handling branches on `code`, never on `message`


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