Overview
The Manza 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 Manza” to first production transaction:
- Create a workspace — sign up and complete activation.
- Test in the sandbox — see the Sandbox & test cards guide.
- Generate an API key from Settings → Developer → API Keys.
- Make your first request to confirm the key works.
- Build against staging, then mint a production key and switch base URL.
curl https://za.manza.finance/api/entity \
-H "Authorization: Bearer sk_live_..."manza login
manza entity getimport { Manza } from "@getmanza/sdk";
const manza = new Manza({ apiKey: process.env.MANZA_API_KEY });
await manza.entity.get();require "manza"
manza = Manza.new(api_key: ENV["MANZA_API_KEY"])
manza.entity.getfrom manza import Manza
client = Manza() # reads MANZA_API_KEY
client.entity.get()import manza "github.com/getmanza/manza-go"
client, _ := manza.New(manza.WithAPIKey(os.Getenv("MANZA_API_KEY")))
entity, err := client.Entity.Get(ctx)let client = manza::Client::builder()
.api_key(std::env::var("MANZA_API_KEY")?)
.build()?;
let entity = client.entity().get()?;{:ok, client} = Manza.new(api_key: System.fetch_env!("MANZA_API_KEY"))
{:ok, entity} = Manza.Entity.get(client)require "manza"
client = Manza::Client.new # reads MANZA_API_KEY
entity = client.entity.getuse Manza\Client;
$client = new Client(apiKey: getenv('MANZA_API_KEY'));
$entity = $client->entity->get();Generating an API key#
To generate an API key:
- Open Settings → Developer → API Keys in the Manza dashboard.
- Click Create API Key.
- Name the key (e.g. “Production”, “Staging”, “My App”) and select the scopes it needs (see Scopes below).
- List the IP addresses the key may be used from (see IP allowlist below). This is required for a key with transfers:authorize and optional for any other key. Then confirm with your verification code.
- Copy the key immediately — it is shown only once. Store it in a secrets manager.
- Use it in requests as
Authorization: Bearer <key>.
Environments#
Production handles real money. The sandbox has separate data, dashboards and API keys; a key from one environment does not authenticate in another. Build and test against the sandbox, then generate a production key and switch your base URL. Examples on these pages use the host you are currently viewing, with /api as the API prefix.
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 — Manza never stores your key in plaintext.
IP allowlist#
A key can be locked to your servers' addresses. Set the list in Settings → Developer → API Keys, on the key's page: one IPv4 or IPv6 address or CIDR network per line, up to 20. A bare address means that one host (/32 or /128). A request with the key from any other address is refused with 403 ip_not_allowed, on every endpoint.
Only a legal representative or manager can set or change the list, and only in the dashboard with a verification code. The API cannot read or change it. Every change notifies the members who approve payments.
A key with transfers:authorize must have a list. Other keys may leave it empty, which allows any address. A network that covers every address (0.0.0.0/0 or ::/0) is refused: it would look like a restriction without being one, so leave the list empty instead. Use static egress addresses: a NAT gateway, a fixed proxy, or your hosting provider's published ranges.
Versioning#
The API uses date-based versioning via the Manza-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.
The original Zazu-Version header is still accepted and responses echo both. It is deprecated — pin new clients to Manza-Version.
Rate limiting#
The general limit is 120 requests per minute per API key. Transfer initiation (POST /api/payments) also has a stricter 10 requests per minute limit. Exceeding a limit returns 429 with error.type: "rate_limit_error". Back off before retrying; spread work over time rather than retrying in a tight loop.
Errors#
All errors follow a consistent envelope format:
{
"error": {
"type": "validation_error",
"message": "Customer not found",
"param": "customer_id"
}
}| Type | HTTP | Description |
|---|---|---|
invalid_request_error | 400 | Malformed JSON or missing required parameters |
invalid_version | 400 | Unsupported Manza-Version header |
authentication_error | 401 | Missing or invalid API key |
entity_inactive | 403 | Entity has not completed activation |
forbidden_error | 403 | API access or feature not enabled |
insufficient_scope | 403 | API key lacks required scope |
ip_not_allowed | 403 | API key used from an address outside its IP allowlist |
not_found_error | 404 | Resource does not exist |
conflict | 409 | Resource conflict, such as an existing credit note |
state_error | 422 | Invalid state transition |
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, ordered by ID descending. Supply limit (default 25, clamped to 1–100) and an optional cursor. Treat the cursor as opaque; an invalid cursor returns 400 invalid_request_error.
GET /api/accounts?limit=10The response contains data (the current page), has_more and next_cursor. When has_more is true, pass next_cursor in the next request:
GET /api/accounts?limit=10&cursor=PASTE_NEXT_CURSOR_HEREContinue until has_more is false; next_cursor is then null. Send your Bearer token with every request.
{
"data": [],
"has_more": false,
"next_cursor": null
}Scopes#
Choose scopes when creating an API key. Existing keys do not gain new scopes when another product is released. If a request returns 403 insufficient_scope, create a new key with the required permissions, update your integration and revoke the old key when it is no longer used.
| Scope | Permission |
|---|---|
entity:read | Retrieve your entity |
accounts:read | Read accounts and their transactions |
transfers:read | Retrieve an API-created payment |
transfers:write | Submit a payment into the dashboard approval flow |
transfers:authorize | Authorize or decline transfer authorization challenges; never on the key that created the transfer |
beneficiaries:read | Read beneficiaries and their bank accounts |
beneficiaries:write | Create beneficiaries and their bank accounts |
beneficiaries:request_trust | Ask approvers to trust payees for machine-approved transfers |
bulk_payments:read | Registered scope; no public REST bulk-payment endpoint |
bulk_payments:write | Registered scope; no public REST bulk-payment endpoint |
invoices:read | List and retrieve invoices |
invoices:write | Create, update, delete invoices and create credit notes |
invoices:send | Send, mark paid and cancel invoices |
invoices:auto_approve | Automatically approve and send API-created invoices, bypassing approval rules |
customers:read | List and retrieve customers |
customers:write | Create, update and delete customers |
payment_links:read | List and retrieve hosted payment URLs |
payment_links:write | Create and cancel hosted payment URLs, including invoice links |
checkout_sessions:read | Retrieve hosted checkout records |
checkout_sessions:write | Create hosted checkout records |
webhook_endpoints:read | List and retrieve webhook endpoints |
webhook_endpoints:write | Create, update, delete, test, enable or disable endpoints and rotate secrets |
This catalogue lists registered permissions; product availability is checked separately. invoices:auto_approve supplements invoices:write; it does not grant invoice creation by itself.
Entity#
GET /api/entity returns the entity associated with your API key. Required scope: entity:read. Use the authenticated request in Getting started above. A successful response is 200 OK:
{
"id": "01964a3b-0000-7000-8000-000000000001",
"name": "Acme Corp",
"created_at": "2026-01-15T10:30:00Z"
}id is the entity identifier, name its name, and created_at an ISO 8601 timestamp.
Feature access#
API access must be enabled for your entity, and the entity must have completed activation. Product access and key scopes are checked independently: granting a scope does not enable a product. An unavailable feature returns 403 forbidden_error; incomplete activation returns 403 entity_inactive.
| Access requirement | Applies to |
|---|---|
| API access | All API endpoints |
| Invoicing | Invoice and customer endpoints |
| Card collection | Payment-link and checkout-session endpoints |
| Transfer initiation | Payment creation and retrieval, and beneficiary and bank-account creation and lookup |
Contact support if the product you need is unavailable. Public docs follow the deployment's released products; your entity can still have additional access restrictions.