Tezos
Tezos Reveal
On Tezos, an account that has never originated an outgoing operation has its public key only implied by its address hash. Before such an account can sign anything the network must verify, the public key has to be revealed on-chain — exactly once. Subsequent operations are then validated against that revealed key.
Custody exposes this one-time setup as:
- a write endpoint that initiates a
revealcustody transaction (subject to your vault’s normal approval workflow); - a read endpoint that returns whether a given address is currently revealed on the ledger.
Carabaas Custody also enforces an implicit guard on every regular Tezos transfer: outbound transactions from an un-revealed source are rejected at the API boundary. Plan your flow accordingly — see Reveal-before-transfer guard below.
Authentication: all calls require a valid JWT (same scheme as the rest of the Custody API).
Reveal-before-transfer guard
When you submit a regular Tezos transfer (POST /api/v1/transactions) and the source address is not yet revealed, the API rejects the request with HTTP 400 and the message Address is not revealed — the transfer is not created.
What this means for integrators:
- The very first outbound activity of any Tezos vault address must be a reveal transaction. Only after it is confirmed on-chain can transfers from that address be initiated.
- The check uses the same on-chain probe as the status read endpoint and adds a small Argus round-trip to every Tezos transfer creation; this is normal.
- If your application creates an address and immediately tries to send from it, expect a 400 until reveal is confirmed.
- Reveal status is per-address, persisted on-chain; once revealed, the address stays revealed forever.
A safe sequencing pattern:
- Create / select the Tezos source address.
GET /addresses/{id}/is-revealed→ iffalse, continue; otherwise skip to step 5.POST /transactions/reveal.- Wait for the reveal transaction to reach
confirmed(via webhooks / event stream). - Submit transfers as usual.
Check if an address is revealed
Request
curl -H "Authorization: Bearer $TOKEN" \
https://api.carabaas.com/api/v1/addresses/{addressId}/is-revealed
| Method | GET |
| Path | /api/v1/addresses/{addressId}/is-revealed |
| Path parameter | addressId — Custody address resource id |
No query parameters.
Authorization
The caller must satisfy either:
manageVaultspermission on the address’s organization, orreadpermission on the address’s vault.
Success response
- HTTP 200
- Body shape:
{ "data": { … } }
{
"data": {
"network": "tezos-mainnet",
"addressId": "8uPDmg3KsbUfsB8dx",
"networkAddress": "tz1abc...",
"revealed": true
}
}
| Field | Meaning |
|---|---|
network | Custody network code of the address. |
addressId | The same Custody address resource id you queried. |
networkAddress | The on-chain Tezos address (tz1… / tz2… / tz3… / KT1…). |
revealed | true if the public key is revealed on-chain, otherwise false. |
The probe queries chain state (via Custody’s wallet/indexer pipeline) at the time of the call — there is no caching layer between you and the ledger view, so it is suitable for gating UI actions such as enabling a “Send” button.
Error responses
| HTTP | When |
|---|---|
| 400 | The address is not on a Tezos network (Only Tezos network is supported for this operation). |
| 400 | The network is a virtual/test pseudo-network (Virtual networks are not supported for this operation). |
| 400 | The address’s vault is paused, archived, or has no wallet attached (Vault is not active). |
| 403 | Caller lacks both manageVaults (org) and read (vault) permissions. |
| 404 | addressId does not exist in your organization scope. |
Create a reveal transaction
Run reveal before the first outgoing transfer from a Tezos address. Submitting a transfer from an un-revealed address fails with HTTP 400 (see Reveal-before-transfer guard).
Request
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"orderId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"addressId": "8uPDmg3KsbUfsB8dx",
"network": "tezos-mainnet"
}' \
https://api.carabaas.com/api/v1/transactions/reveal
| Method | POST |
| Path | /api/v1/transactions/reveal |
| Body | JSON (see below) |
JSON body fields
| Field | Required | Description |
|---|---|---|
orderId | Yes | A valid UUID string. Used as an idempotency key: repeating the same orderId does not create a second transaction (see Idempotency). |
addressId | Yes | Custody address resource id — the Tezos account that should be revealed. Must belong to an active vault that has a wallet attached. |
network | Yes | Custody network code for a Tezos ledger (e.g. tezos-mainnet). Virtual/test pseudo-networks are not accepted. |
feePriority | No | One of low, medium, high. If omitted, the API applies its default fee behaviour for that network. |
There is no asset field — reveal is asset-less; the operation pays its fee in XTZ, so the address must hold a small amount of XTZ to cover the fee before you submit.
Authorization
The caller must have initiate permission on the vault owning addressId. Without it the request is rejected with 403 before any transaction is created.
Idempotency and response codes
The JSON envelope follows the usual API pattern: { "data": { …transaction… } }. The HTTP status code distinguishes create vs replay — read it explicitly in addition to the body:
| HTTP | Meaning |
|---|---|
| 201 | A new reveal transaction was created for this orderId. |
| 200 | A transaction with this orderId already exists (idempotent retry); the same transaction object is returned. |
Replays return the existing transaction regardless of its current status (pending, approved, broadcast, confirmed, failed, …), so data.status is the canonical signal for progress.
The returned transaction object has type: "reveal" and amount: "0" (a reveal carries no value transfer). It then moves through the same lifecycle as any other custody transaction: pending → approved (once vault quorum is met) → signing → broadcast → confirmed (or failed on rejection). Subscribe via your usual transaction-event channel (webhooks / event stream) to track it; do not assume the address is revealed until status is confirmed.
The reveal endpoint does not check current on-chain state before creating the transaction. If the address is already revealed on-chain, your reveal transaction will be rejected by the network at broadcast time and end up in
failedstatus. UseGET /addresses/{id}/is-revealedfirst if you want to avoid this.
Error responses
All validation errors return HTTP 400 with a descriptive message. Common cases:
| Cause | Message contains |
|---|---|
network is not Tezos | Network ... is not allowed for this operation |
network is a virtual/test pseudo-network | Virtual networks are not supported for this operation |
| Vault is paused, archived, or has no wallet attached | Vault is not active |
Caller lacks initiate on the vault | Access denied (HTTP 403) |
addressId does not exist | (HTTP 404) |
Schema-level violations (missing field, malformed UUID, wrong types) are rejected by request validation before any of the above and surface as a generic 400 with a Zod-style error.
Integration notes
- Fresh UUIDs, careful retries — Generate a fresh UUID per logical “reveal address” business action. On timeouts/network errors reuse the same
orderIdso retries don’t spawn duplicates: the server treats the retry as a no-op and returns the existing transaction with HTTP 200. - Fund before reveal — A reveal still pays a small XTZ fee. Make sure the address holds enough native XTZ before you submit, otherwise the on-chain submission stage will fail even though the API call succeeds.
- One reveal per address, ever — Reveal is idempotent on chain only in the trivial sense that the network rejects double-reveals. Don’t treat reveal as something you may need to repeat; check status first if in doubt.
- Approvals required — Like any custody transaction, a
revealmay need vault-quorum approvals before signing. Wire it through the same approval/notification path you already use for transfers. - Gate “Send” UI on reveal — If your product surfaces a “Send” action for Tezos addresses, gate it on
revealed === true(or on a successful,confirmedreveal in your own bookkeeping) to avoid hitting the reveal-before-transfer guard. - Tezos only — Both endpoints reject other networks with 400.