MoniWave

Authentication

Every /v1 request authenticates with a secret API key as a bearer token:

Authorization: Bearer sk_test_4f8Xk2mQ9pL7vR3nT6wY1zB5cD8eF0gH

There is no token exchange, no signing ceremony, no expiry to manage — one header, every request.

Key format

PrefixMeaning
sk_test_Secret key, sandbox. Safe to use against the sandbox base URL only.
sk_live_Secret key, live. Moves real money.
pk_test_ / pk_live_Publishable keys — reserved for a future browser-side SDK. Not issued today, and not used for API authentication.

Secret keys are 40 characters: the prefix plus 32 random alphanumeric characters.

Hosted checkout needs no browser-safe key: the merchant's server creates a session with its secret key, and the resulting one-time session token authorises exactly that one payment.

Keeping keys secret

  • Server-side only. A secret key in browser JavaScript, a mobile app binary, or a public repository is compromised — rotate it immediately.
  • We store only a SHA-256 hash of your key, so we cannot recover it for you. The plaintext is shown once, at issuance.
  • The sk_live_ prefix is deliberately scannable: secret-scanning tools (GitHub push protection and similar) can catch a leaked live key before it reaches a public repository.

Who may manage keys

Issuing and revoking keys requires the Admin or Owner role. A secret key authenticates the whole money surface, so minting one sits with the roles that manage the team and the money.

Developer members can still see the key list — labels, environment, expiry and last use — so they can tell which key a service is using and when it runs out. They cannot create or revoke one.

Key lifetime

Every key expires, at most 180 days after it was issued. There is no grace period: past its expiry a key answers api_key_expired (401) and stops authenticating. The expiry date is shown against each key in the dashboard.

A key never has to be used to stay valid, and a leaked one is indistinguishable from a real one over TLS — so a key that never expires is a credential with no bound on how long a leak stays useful. Rotate on a schedule you control rather than on the deadline.

Keys issued before this policy existed run on the same 180-day clock, measured from when they were actually issued.

Rotating keys

A merchant can hold at most two active keys per environment — enough for zero-downtime rotation, and few enough that every live key is one somebody can account for. Test and live keys are counted separately.

  1. Issue a new key in the dashboard.
  2. Deploy it to your servers.
  3. Confirm the old key has stopped being used (the dashboard shows last-used time).
  4. Revoke the old key.

Revocation takes effect immediately, and frees the slot. So does expiry — a key that has run out no longer counts against the limit, so you are never blocked from issuing a replacement.

Issuing a third active key in one environment is refused with key_limit_reached.

Errors

HTTPCodeMeaning
401missing_api_keyNo Authorization header.
401invalid_api_keyUnknown, malformed, or revoked key.
401api_key_expiredThe key was valid and has passed its expiry. Issue a replacement in the dashboard.
401environment_mismatchRight key, wrong base URL — e.g. a sk_live_ key sent to the sandbox. The message states which key the URL expects.

All follow the standard error envelope.

{
  "error": {
    "code": "environment_mismatch",
    "message": "You used a live key against the test API. Use your sk_test_ key with this base URL.",
    "details": []
  }
}

Going live

Going live is a base-URL and key swap, and nothing else — no code changes, no different request shapes, no separate integration:

- https://api-sandbox.moni-wave.com   sk_test_…
+ https://api.moni-wave.com           sk_live_…

While the sandbox is in preview it answers on https://api-dev.moni-wave.com instead; the swap has the same shape either way, and the examples throughout these pages use the preview host so they run as written. See Base URLs.

Sandbox and live are separate environments with separate data: sandbox transactions, merchants, and keys do not exist in live. The sandbox runs the deterministic simulator instead of real mobile-money operators; everything else — API behaviour, statuses, webhook format, error codes — is identical, which is what makes the swap safe.

Keys never cross environments. A sandbox key cannot move real money even if leaked, and a live key against the sandbox URL is rejected with environment_mismatch rather than silently doing nothing.