Developer Docs

# Overview

The Zazu API lets you programmatically manage accounts and transfers, and subscribe to signed webhooks. It follows RESTful conventions with JSON request and response bodies.

## Getting started

The path from “I want to try Zazu” to first production transaction:

1. Create a workspace — sign up and complete activation.
2. Test in the sandbox — see the Sandbox & test cards guide.
3. Generate an API key from Settings → Developer → API Keys.
4. Make your first request to confirm the key works.
5. Build against staging, then mint a production key and switch base URL.

cURL

CLI

JavaScript

Ruby

Python

Go

Rust

Elixir

Crystal

PHP

```console
curl https://zazu.africa/api/entity \
  -H "Authorization: Bearer sk_live_..."
```

```console
zazu login
zazu entity
```

```javascript
import { Zazu } from "@getzazu/sdk";
const zazu = new Zazu({ apiKey: process.env.ZAZU_API_KEY });

await zazu.entity.retrieve();
```

```ruby
require "zazu"
zazu = Zazu.new(api_key: ENV["ZAZU_API_KEY"])

zazu.entity
```

```python
from zazu_sdk import Zazu
client = Zazu(api_key="sk_live_...")

client.entity.retrieve()
```

```go
import zazu "github.com/getzazu/zazu-go"

client, _ := zazu.New(zazu.WithAPIKey(os.Getenv("ZAZU_API_KEY")))

entity, err := client.Entity.Get(ctx)
```

```rust
let client = zazu_sdk::Client::builder()
    .api_key(std::env::var("ZAZU_API_KEY")?)
    .build()?;

let entity = client.entity().get()?;
```

```elixir
{:ok, client} = Zazu.new(api_key: System.fetch_env!("ZAZU_API_KEY"))

{:ok, entity} = Zazu.Entity.get(client)
```

```crystal
require "zazu"

client = Zazu::Client.new # reads ZAZU_API_KEY

entity = client.entity.get
```

```php
use Zazu\Client;

$client = new Client(apiKey: getenv('ZAZU_API_KEY'));

$entity = $client->entity->get();
```

## Generating an API key

Your browser does not support the video tag. 

Download the video

.

To generate an API key:

1. Open Settings → Developer → API Keys in the Zazu dashboard.
2. Click Create API Key.
3. Name the key (e.g. “Production”, “Staging”, “My App”) and select the scopes it needs (see Scopes below).
4. Copy the key immediately — it is shown only once. Store it in a secrets manager.
5. Use it in requests as `Authorization: Bearer <key>`.

## Authentication

API keys authenticate requests via a Bearer token in the `Authorization` header. Keys use the `sk_live_` prefix and are hashed with SHA-256 before storage — Zazu never stores your key in plaintext.

> **Keep keys secret:** Never expose keys in client-side code, public repos, or logs. If a key is compromised, revoke it immediately from the dashboard.

> **Server-side only:** The API is meant to be called from your backend, not from browser JavaScript. It sends no CORS headers, so cross-origin requests are blocked.

## Versioning

The API uses date-based versioning via the `Zazu-Version` header. If omitted, the current version is assumed. Breaking changes ship under a new version date with a migration guide; non-breaking changes (new fields, new endpoints) apply to all versions.

## Errors

All errors follow a consistent envelope format:

```json
{
  "error": {
    "type": "validation_error",
    "message": "Customer not found",
    "param": "customer_id"
  }
}
```

| Type | HTTP | Description |
| --- | --- | --- |
| `invalid_request_error` | 400 | Malformed JSON or missing required parameters |
| `authentication_error` | 401 | Missing or invalid API key |
| `forbidden_error` | 403 | API access or feature not enabled |
| `insufficient_scope` | 403 | API key lacks required scope |
| `not_found_error` | 404 | Resource does not exist |
| `validation_error` | 422 | Invalid request parameters |
| `rate_limit_error` | 429 | Too many requests |
| `api_error` | 500 | Internal server error |

## Pagination

List endpoints use cursor-based pagination for reliable results even with concurrent inserts or deletes. Requests are rate-limited to 120 requests per minute per API key.

```json
{
  "data": [ ... ],
  "has_more": true,
  "next_cursor": "eyJpZCI6IjAxOTY0..."
}
```

## Scopes

API keys are created with specific scopes that control which endpoints they can access. Scopes are fixed at key creation — using a new product with a key that lacks its scope returns `403 insufficient_scope`.