Guide

# Sandbox & test cards

Manza provides a sandbox environment so you can integrate, test edge cases, and verify webhook handling without moving real money or charging real cards.

## Accessing the sandbox

Use the Manza sandbox for your region. Sandbox and production data are isolated: API keys, customers, payments and webhook endpoints from one environment do not appear in the other. Use a key created in the same sandbox as your API base URL.

| Region | Sandbox dashboard | Sandbox API base |
| --- | --- | --- |
| Morocco | [ma.manza.dev](https://ma.manza.dev) | `https://ma.manza.dev/api` |
| South Africa | [za.manza.dev](https://za.manza.dev) | `https://za.manza.dev/api` |

Open **Settings → Developer → API Keys** in that sandbox dashboard and create a dedicated key. Select `entity:read` for the first request below, plus the [scopes](https://ma.manza.dev/docs/overview#scopes) needed by your integration. Copy the key when it is shown and store it securely; do not place it in browser code or source control.

## Verify API access

Set `MANZA_API_KEY` in your backend environment to your sandbox key. Set `MANZA_BASE_URL` to `https://ma.manza.dev` for Morocco or `https://za.manza.dev` for South Africa — the host without the `/api` suffix, which is what the official SDKs read (they append `/api/...` themselves). Then make this read-only request:

```shell
curl "$MANZA_BASE_URL/api/entity" \
  -H "Authorization: Bearer $MANZA_API_KEY"
```

A `200` response returns the workspace associated with your key. Confirm it is the workspace you intended before continuing. API access and workspace activation must be enabled in the sandbox; creating a key does not enable product access.

| Response | What to check |
| --- | --- |
| `401` | Check the Bearer token and confirm the key was created in this sandbox, not production or the other region. |
| `403` with `error.type` = `insufficient_scope` | Create a key with the endpoint's required scope. Existing keys do not gain new scopes automatically. |
| `403` with `error.message` = `Feature not enabled` or `API access not enabled` | Ask support to enable the required access for your sandbox workspace. Share the workspace and sandbox URL, never the API key. |
| `403` with `error.type` = `entity_inactive` | Complete workspace activation or ask support about activation of your sandbox workspace. |

Product [feature access](https://ma.manza.dev/docs/overview#feature-access) and API-key scopes are checked separately. A successful entity request verifies authentication and basic API access; it does not prove every product endpoint is enabled. Follow the relevant API reference for its required scopes and approval flow.

## Test cards

Use these card numbers on any sandbox hosted payment page. Any future expiry date, any 3-digit CVC, and any postcode are accepted.

| Card number | Brand | Result |
| --- | --- | --- |
| `4242 4242 4242 4242` | Visa | Payment succeeds |
| `5555 5555 5555 4444` | Mastercard | Payment succeeds |
| `4000 0000 0000 0002` | Visa | Card declined |

> **Note:** Real card numbers are never charged on the sandbox. Submitting one returns a generic decline.

## Reconciling payment state

Two ways to confirm whether a sandbox payment succeeded:

- **API** — GET the checkout session or payment link and check the status field.
- **Webhooks** — listen for checkout_session.completed or payment_link.paid. Sandbox webhooks fire identically to production, signed with the same scheme.

> **Tip:** Webhooks are the source of truth for fulfillment. Use the API endpoints for reconciliation or recovery when a webhook is missed.

A confirmed payment first reads `clearing` (credited, provider settlement pending, `settled_at` null) — sandbox included. Fulfill on `checkout_session.completed` / `payment_link.paid`; if you also track settlement, listen for `checkout_session.settled` / `payment_link.payment_settled`, which fire once `settled_at` is set.

## Going live

When your sandbox integration is stable:

1. Mint a fresh API key from the production dashboard (production keys can't be cloned from sandbox).
2. Switch your application's base URL from the sandbox host to production.
3. Replace test-card flows with real card collection (the hosted page handles PCI).
4. Re-register your webhook endpoint against the production dashboard.