Getting started
Base URL & versioning
| Environment | Base URL |
|---|---|
| Staging | https://api-staging.zenvault.io/api |
| Production | https://api.zenvault.io/api |
All integration endpoints live under /v1, e.g. POST /api/v1/transfers/external.
The health check is unauthenticated: GET /api/health.
Requests and responses are JSON (Content-Type: application/json). IDs are
UUIDs. Monetary amounts are decimal strings (e.g. "125.50"), never floats —
preserve them as strings end to end.
Authenticate
Every /v1 request carries your workspace API key as a bearer token:
Authorization: Bearer zv_a1b2c3d4_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
The key has the form zv_<8-char-prefix>_<secret>. ZenVault stores only a hash
of the secret — the full key is shown once, at creation. Put it in your
secret manager; if lost, it must be rotated, not recovered.
Try it against the health check first (no auth needed), then a real endpoint:
curl -fsS https://api-staging.zenvault.io/api/health
# → {"status":"ok","db":"up",...}
curl -fsS https://api-staging.zenvault.io/api/v1/assets \
-H "Authorization: Bearer $ZENVAULT_API_KEY"
A missing or invalid key returns 401; a valid key without the required
scope returns 403.
The shape of an integration
- Create a vault —
POST /v1/accounts, choosing a vault type. - Activate assets on it and generate deposit addresses.
- Receive deposits — ZenVault confirms them and fires an
address.receivedwebhook. - Send withdrawals —
POST /v1/transfers/external, tracked through the transfer state machine. - React to events via signed webhooks rather than polling.
Continue to the Quickstart for a runnable end-to-end example, or read Core concepts first.