Addresses
An address is the on-chain endpoint your vault uses to receive deposits and send funds. Every address is deterministically derived from the vault's master key using BIP-44 (soft derivation) and is bound to a single account inside the vault.
Each address is represented by a stable platform-side ID (id) plus the chain-native address string (networkAddress); the API always works with id — networkAddress is for human display and on-chain interactions.
How addresses are derived
The platform builds an address from a 5-component HD path:
m/44/<coinType>/<accountIndex>/<change>/<addressIndex>
| Component | Default | What it controls |
|---|---|---|
coinType | the network's SLIP-44 (e.g. 60 for Ethereum, 0 for Bitcoin) | The chain "namespace" inside BIP-44. |
accountIndex | from the account's index (set when the account is created) | Logical account within the vault — same for every address of that account. |
change | 0 | 0 = external/receiving address, 1 = internal/change address. |
addressIndex | next free index for this (account, coinType, change) | Per-account counter; the platform allocates the next value automatically. |
type | network-specific (e.g. p2wpkh for Bitcoin) | Address format. See Address types. |
When you call POST /addresses without any of coinType, change, addressIndex, the platform picks the defaults above and allocates the next free addressIndex. To target a specific HD path slot, see Custom HD path.
The full HD path is returned on every address as hdpath — useful for audit and reproducibility.
Create an address
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accountId": "eFjwUQXB8CMnrTHSgYzaL6",
"network": "ethereum-mainnet",
"name": "Customer Deposits"
}' \
https://api.carabaas.com/api/v1/addresses
Request body:
| Field | Required | Notes |
|---|---|---|
accountId | yes | Existing account inside an active vault. |
network | yes | Real network (e.g. ethereum-mainnet, bitcoin-mainnet) or the virtual @eth-like (see below). |
name | yes | Human-readable label, unique within the account (3–128 chars). Doubles as an idempotency key — see below. |
type | no | Address format for chains with multiple formats (e.g. p2wpkh, p2pkh for Bitcoin). |
coinType | no | Override the SLIP-44 used in the HD path. If set, change and addressIndex become required. |
change | no | 0 (external) or 1 (internal). Required when coinType or addressIndex is provided. |
addressIndex | no | Pin a specific slot. If set, change becomes required. |
data | no | Free-form JSON object you can attach to the address (e.g. your internal customer ID). |
Caller must hold generateDetails permission on the address's vault.
Response codes
201 Created— a new HD slot was allocated and an on-chain address was generated.200 OK— an address with thisnamealready exists in the account and all provided parameters match — the existing record is returned as-is. Use this to make creation idempotent: re-issuing the same request after a network blip is safe.409 Conflict— a name conflict where parameters differ (e.g. samenamebut a differentnetworkoraddressIndex), or an HD-path conflict that violates address exclusivity.
Idempotency by name
name is unique per account and acts as the client-side idempotency key. The platform uses it to recognize a retried request and return the existing address instead of generating a new one — provided every supplied attribute matches the stored record (network, type, coinType, change, addressIndex, data).
Two practical consequences:
- Always pick a name that uniquely identifies the address from your side (a customer ID, a deposit-flow tag, etc.).
- If you change any parameter under the same name, you'll get
409 ADDRESS_AMBIGUOUS— pick a different name instead.
Address types
Address type controls the on-chain address format. It only matters for chains that support multiple formats.
| Network | Allowed type | Default if omitted | Notes |
|---|---|---|---|
| Bitcoin & UTXO forks | p2wpkh, p2pkh | none — type is required | See Bitcoin & UTXO Chains. |
| Account-based chains (Ethereum, Solana, Tron, etc.) | (omit) | internal default | The chain has only one address format; you don't need to set type. |
Two addresses can coexist at the same HD-path slot if their type differs (e.g. a p2pkh and a p2wpkh Bitcoin address derived from the same path are independent on-chain addresses).
ETH-like universal addresses
Most EVM chains share an identical address derivation. Instead of generating a separate address per chain, you can target the virtual network @eth-like:
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accountId": "eFjwUQXB8CMnrTHSgYzaL6",
"network": "@eth-like",
"name": "Universal EVM Address"
}' \
https://api.carabaas.com/api/v1/addresses
A single @eth-like address is reachable on Ethereum, Polygon, BSC, Arbitrum, Optimism, Avalanche, and every other EVM-compatible chain the platform supports — present and future. Balances returned for it (see Get an address with balances) aggregate across all those chains.
Upgrading an existing chain-specific address
If you already created an address for a single EVM chain (say ethereum-mainnet) and later want it to receive on every EVM chain, repeat the create call with the same name but network: "@eth-like":
curl -X POST -d '{
"accountId": "...",
"network": "@eth-like",
"name": "Customer Deposits" # same name as the existing ethereum-mainnet address
}' ...
The platform recognizes the request as an in-place upgrade: the address keeps its id and networkAddress, but its network field flips to @eth-like and the address starts being recognized on every EVM chain. The reverse — downgrading @eth-like to a single chain — is not supported.
Address exclusivity
A single HD-path slot (the (account, coinType, change, addressIndex, type) tuple) can hold either one virtual address or one or more non-virtual addresses on different chains — never both at the same time.
In practice this means:
- If you have an
@eth-likeaddress at a given slot, you cannot create a chain-specific (e.g.polygon-mainnet) address at the same slot. Use the virtual address — it already covers Polygon. - If you have one or more chain-specific addresses at a slot (e.g.
ethereum-mainnetandbitcoin-mainnet— yes, they live at differentcoinTypevalues, so this example would be at different slots; but two ETH-only addresses on different EVM networks would share a slot), you cannot create an@eth-likeaddress at that slot until you upgrade one of them as described above.
A violation surfaces as 409 with code ADDRESS_AMBIGUOUS.
Custom HD path
You can pin one or more HD-path components instead of letting the platform pick them:
{
"accountId": "eFjwUQXB8CMnrTHSgYzaL6",
"network": "ethereum-mainnet",
"name": "Reserve Wallet #5",
"coinType": 60,
"change": 0,
"addressIndex": 5
}
Constraints:
coinType: integer,0 ≤ coinType ≤ 2_147_483_647. If provided, bothchangeandaddressIndexmust also be provided.change: integer,0or1.addressIndex: integer,0 ≤ addressIndex ≤ 2_147_483_647. If provided,changemust also be provided.
Pinning addressIndex to a value below the current platform-allocated counter is allowed — the next auto-allocation simply jumps to max(currentPointer, pinnedIndex) + 1 so you don't get collisions.
Get an address with balances
curl -H "Authorization: Bearer $TOKEN" \
https://api.carabaas.com/api/v1/addresses/{addressId}
The response is the address record plus a balances array — one entry per (network, asset) the address holds. For an @eth-like address you'll see one entry per EVM chain on which the address has any balance.
Update an address
You can rename or update the attached data; the on-chain address itself is immutable.
curl -X PATCH \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Customer Deposits — archived",
"data": { "archivedAt": "2026-04-29" }
}' \
https://api.carabaas.com/api/v1/addresses/{addressId}
Both fields are optional. name must remain unique within the account (409 Conflict otherwise). Caller needs edit on the vault.
List addresses
curl -H "Authorization: Bearer $TOKEN" \
"https://api.carabaas.com/api/v1/addresses?organizationId=djk2wDuMhsx9KR2r7JgBQW"
organizationId is required. Results are scoped automatically to vaults the caller can read; without Vault:read (global) or manageVaults on the org, the list is restricted to vaults explicitly granted to the caller.
Query parameters
| Parameter | Type | Notes |
|---|---|---|
organizationId | string | Required. |
filter[vaultId] | string[] | Filter by vault IDs. |
filter[accountId] | string[] | Filter by account IDs. |
filter[network] | string[] | Filter by networks. A real EVM network (e.g. polygon-mainnet) automatically also matches @eth-like addresses, since those addresses are reachable on that network. |
filter[addressIndex] | number[] | Filter by HD-path addressIndex. |
filter[format] | string[] | Filter by address type (p2wpkh, p2pkh, default). |
relations[] | enum[] | Include related entities. Supported: account, balances. balances requires a single value in filter[vaultId] (otherwise the request is rejected). |
search | string (≥ 3) | Substring match on name, networkAddress, or hdpath. |
page | number | Default 0. |
pageSize | number | Default 100, max 1000. |
# Filter by vault
curl "...?organizationId=djk2wDuMhsx9KR2r7JgBQW&filter[vaultId][]=kR7mNpX2wQvL9sYhBjD4eT"
# Search by name, address, or HD path
curl "...?organizationId=djk2wDuMhsx9KR2r7JgBQW&search=customer"
# Include balances (single vault required)
curl "...?organizationId=djk2wDuMhsx9KR2r7JgBQW&filter[vaultId][]=kR7mNpX2wQvL9sYhBjD4eT&relations[]=balances"
Validate / canonicalize an address
Before using a third-party destination, run it through the canonicalizer to (a) check it parses for the target network and (b) get the platform's preferred form back:
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"network": "ethereum-mainnet",
"address": "0x742d35Cc6634C0532925a3b8..."
}' \
https://api.carabaas.com/api/v1/addresses/canonicalize
{
"data": {
"canonical": "0x742d35cc6634c0532925a3b8...",
"formats": [ { "format": "checksum", "address": "0x742d35Cc..." } ],
"features": { "requireMemo": false },
"metadata": { /* network-specific metadata, e.g. account flags */ }
}
}
What you get:
canonical— the form the platform stores and matches against (e.g. lowercase for EVM, base58check for Bitcoin).formats— alternative valid renderings of the same address.features.requireMemo— for chains where the destination demands a memo/destination tag (currently surfaced for Ripple, derived from the on-chainrequireDestinationTagflag). Treattrueas a hard signal to require amemoon every transaction to that address.metadata— chain-specific extras (account flags, sequence numbers, …).
The endpoint is rejected (404) for virtual networks like @eth-like. An invalid address returns 400 Invalid address provided.
Always canonicalize external destinations before creating a transaction or saving them to an address book.
ERC-20 / TRC-20 allowance
Inspect how much a third-party spender is allowed to pull from one of your addresses for a given token contract:
curl -H "Authorization: Bearer $TOKEN" \
"https://api.carabaas.com/api/v1/addresses/{addressId}/allowance?network=ethereum-mainnet&spender=0xSpender...&asset=c60_t0x779877A7B0D9E8603169DdbD7836e478b4624789"
Query parameters (all required):
| Parameter | Description |
|---|---|
network | An ETH-like network or tron-*. Virtual networks are not supported. |
spender | The third-party address allowed to spend. |
asset | A platform asset ID for an ERC-20 or TRC-20 token. |
For setting / changing allowances, see Ethereum & EVM Chains — ERC-20 allowances.
Stellar trustlines
For Stellar addresses you can list the trustlines currently configured on-chain:
curl -H "Authorization: Bearer $TOKEN" \
https://api.carabaas.com/api/v1/addresses/{addressId}/trustlines
Returns an array of platform asset IDs (one per trustline). Only stellar-* addresses are accepted; everything else returns 400.
To open a new trustline, see Stellar & Ripple — Trustlines.
Tezos: check whether an address is revealed
Tezos requires every address to be revealed (its public key published on-chain) before it can sign outgoing operations. Check the current state:
curl -H "Authorization: Bearer $TOKEN" \
https://api.carabaas.com/api/v1/addresses/{addressId}/is-revealed
{ "network": "tezos-mainnet", "addressId": "...", "networkAddress": "tz1...", "revealed": false }
Only Tezos addresses are accepted. To perform the reveal operation, see Tezos Reveal.