{
  "info": {
    "name": "Guveno API",
    "version": "1.10.0",
    "description": "Version 1.10.0 \u00b7 Last updated October 17, 2026.\n\nOfficial Postman collection for the Guveno custody API.\n\nSetup:\n1. Set the collection variable `apiKey` to a key generated in the dashboard (Developer \u2192 API Keys). It looks like `gv_live_...`.\n2. Set `baseUrl` to your server (defaults to https://api.guveno.com/v1).\n\nEvery request inherits Bearer auth from the collection using `{{apiKey}}`. Wallets live in vaults (Vault \u2192 Wallet \u2192 Address): a vault is one recovery phrase with a name and the members who hold a sealed copy of it, which is what decides who can sign; a wallet is one chain/network inside the vault at one derivation path; addresses hang off the wallet. This collection covers the vault and wallet operations an API key performs \u2014 account and organization management (members, billing, MFA) live in the dashboard, not the API. See the developer docs at https://www.guveno.com/docs/.\n\nRate limits: a global ceiling of 300 req/min per IP applies to every endpoint, with a tighter 20/min per-caller limit on value-moving writes (withdrawal prepare/broadcast, wallet create/update/delete).\n\nWallet key files: optional file protection is configured and verified in the dashboard (Profile \u2192 Wallet encryption). Any file format, including an image, is supported (non-empty, up to 20 MiB). If enabled, both the encryption password and exact original file bytes are required by the SDK or CLI to unlock wallet secrets. Never add either credential or a file hash to Postman variables or requests; only encrypted envelopes and signed transactions go to the API. Back up the original file separately; modifying its bytes prevents unlocking. Guveno cannot reset or recover it.\n\nSpending policies: an organization can set limits, an approved address list, business hours and approval quorums in the dashboard (Security \u2192 Policies). They are managed only there, but they apply to every withdrawal an API key prepares or proposes. A refusal is a 403 with `code` (`policy_denied`, `policy_approval_required` or `policy_approvals_pending`) and `policyIds`; nothing is reserved or sent. On `policy_approval_required`, propose the same payout under Withdrawal requests.\n\nAsset lists: each organization has its own asset list (the core assets plus any it adds in the dashboard, Assets). `GET /assets` returns what your organization can see, and a withdrawal or withdrawal request for an asset not on the list is refused with 403. The list itself is managed only in the dashboard.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.guveno.com/v1"
    },
    {
      "key": "apiKey",
      "value": "gv_live_your_key_here"
    },
    {
      "key": "vaultId",
      "value": "3e2b7c8a-0f65-4f7f-9a83-2e33cbe0d1a4"
    },
    {
      "key": "walletId",
      "value": "1"
    },
    {
      "key": "assetId",
      "value": "1"
    },
    {
      "key": "addressId",
      "value": "1"
    },
    {
      "key": "transactionId",
      "value": "1"
    },
    {
      "key": "withdrawalId",
      "value": "1"
    },
    {
      "key": "webhookId",
      "value": "1"
    },
    {
      "key": "deliveryId",
      "value": "1"
    },
    {
      "key": "teamId",
      "value": "1"
    }
  ],
  "item": [
    {
      "name": "Identity",
      "item": [
        {
          "name": "Get current user",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/me",
            "description": "Returns the account the API key belongs to: id, email, the optional firstName/lastName its owner set in the dashboard (null until filled in), the company membership, and your encryption key (public key + password-encrypted private key). The SDK/CLI use the key material to seal/unseal wallet secrets locally. Read-only; account settings are dashboard-only."
          }
        }
      ]
    },
    {
      "name": "Vaults",
      "description": "A vault is the custody boundary: one recovery phrase (identified by its fingerprint), a name, and the members who hold a sealed copy of the phrase \u2014 which decides who can sign. Who can SEE a wallet is decided separately, by the teams the wallet belongs to. Renaming (PATCH /vaults/:id) and archiving (DELETE /vaults/:id) are dashboard-session operations and are not available to API keys, so they are not included here. Who holds a copy of a vault's phrase has no API at all: a copy can only be produced by decrypting an existing one in a holder's browser, so it is shared and removed in the dashboard.",
      "item": [
        {
          "name": "List vaults",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/vaults",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "vaults"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "active",
                  "disabled": true,
                  "description": "active (default) | archived | all"
                }
              ]
            },
            "description": "Returns the vaults the caller can see. An API key sees the vaults of the wallets it was granted `wallets:read` on.\n\nEach vault carries `access` (`full` when the member who created the key holds a sealed copy of the phrase, else `watch_only`), `walletCount` (active wallets) and `visibleWalletCount` (the active wallets the key was granted `wallets:read` on; holding the key signs only these). To list the wallets inside one vault use List wallets with `vaultId`."
          }
        },
        {
          "name": "Get vault",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/vaults/{{vaultId}}",
            "description": "Returns one vault: `id`, `name`, `fingerprint` (hash of the recovery phrase), `status`, `access`, `walletCount`, `visibleWalletCount`, timestamps. A vault decides who can SIGN (key access); who can SEE each wallet is decided by the wallet's teams."
          }
        },
        {
          "name": "Create vault",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/vaults",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "vaults"
              ]
            },
            "description": "Registers a new recovery phrase as an empty vault. `keyFingerprint` is the phrase's fingerprint and `encryptedSecretJson` is YOUR sealed copy of the phrase, encrypted to your own public key on your device; the phrase itself never goes to the API. Add wallets afterwards with Create wallet in existing vault.\n\nRequires the `wallets:create` action. A fingerprint already registered in the company is a 409 (a phrase backs exactly one vault); vault names are unique per company.\n\nMost integrations skip this request: Create wallet (new seed) creates the vault on the fly. The SDK/CLI seal the phrase and compute the fingerprint for you; use them rather than assembling key material by hand.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Treasury\",\n  \"keyFingerprint\": \"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08\",\n  \"encryptedSecretJson\": { \"version\": 2, \"type\": \"x25519-sealed-box\", \"ciphertext\": \"...\" }\n}"
            }
          }
        }
      ]
    },
    {
      "name": "Teams",
      "description": "A team holds a set of wallets, and its members see and act on exactly those. Every company has one default team holding every member, so on plans without the teams feature every member sees every wallet; the Enterprise plan unlocks more teams. Creating teams and moving people or wallets between them are dashboard-session operations and are not available to API keys, so only the reads are here.",
      "item": [
        {
          "name": "List teams",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/teams",
            "description": "Returns the teams the caller can see: every team for owners and admins, otherwise only the teams they belong to. Each carries `isDefault` (the company's fallback team, which can never be deleted; on plans without teams it holds every member and wallet), `memberCount` (people who have joined), `pendingCount` (invites not accepted yet; an invitee sees nothing until they accept) and `walletCount` (active wallets the caller can read)."
          }
        },
        {
          "name": "Get team",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/teams/{{teamId}}",
            "description": "Returns one team with its `members` (userId, email, role, status `active` or `pending`, addedAt) and the `wallets` it can reach (id, name, chain, network, vaultId, vaultName, addedAt). The vault named on each wallet is where custody lives: team access lets you see and use a wallet, a key-access grant on its vault lets you sign for it."
          }
        }
      ]
    },
    {
      "name": "Wallets",
      "item": [
        {
          "name": "Create wallet (new seed)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/wallets",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "wallets"
              ]
            },
            "description": "Registers a wallet from a recovery phrase. `keyFingerprint` + `encryptedSecretJson` (your sealed copy of the phrase, encrypted on your device) identify the seed: if a vault already owns that fingerprint and you hold key access to it, the wallet joins that vault; otherwise a new vault is created, named `vaultName` if given and after the wallet if not. `teamIds` decides which teams can see the wallet; omit it on a plan without teams and it joins your company's default team, which holds every member. Re-importing a seed you do NOT hold access to is a 403.\n\n`derivationPathPrefix` is optional and defaults to the chain standard (ethereum/bsc/polygon/arbitrum m/44'/60'/0'/0, bitcoin m/84'/0'/0'/0 or m/84'/1'/0'/0 on testnet, xrp m/44'/144'/0'/0, tron m/44'/195'/0'/0, solana m/44'/501', ton m/44'/607', polkadot //). Every address must sit at exactly `<prefix>/<accountIndex>` (Polkadot `<prefix><accountIndex>`, Solana `<prefix>/<accountIndex>'/0'`, TON `<prefix>/<accountIndex>'`), else 400. Solana, TON and Polkadot wallets cannot be server-derived (their derivation needs the secret), so their addresses are always registered by the SDK or the dashboard. Guveno phrases are BIP39; TON wallets use SLIP-0010 at m/44'/607'/<index>' with the v4r2 contract, so TON-native wallets such as Tonkeeper, which use their own phrase format, will not import them. A vault holds at most one wallet per chain+network+prefix (409 otherwise), and one on-chain address belongs to one wallet in the company (409 otherwise).\n\nRequires the `wallets:create` action. The SDK/CLI build this payload for you (derive the address, seal the phrase, compute the fingerprint); use them rather than assembling key material by hand.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"treasury-btc\",\n  \"chain\": \"bitcoin\",\n  \"network\": \"mainnet\",\n  \"vaultName\": \"Treasury\",\n  \"keyFingerprint\": \"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08\",\n  \"encryptedSecretJson\": { \"version\": 2, \"type\": \"x25519-sealed-box\", \"ciphertext\": \"...\" },\n  \"teamIds\": [1],\n  \"addresses\": [\n    { \"address\": \"bc1q...\", \"derivationPath\": \"m/84'/0'/0'/0/0\", \"accountIndex\": 0, \"label\": \"main\" }\n  ]\n}"
            }
          }
        },
        {
          "name": "Create wallet in existing vault",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/wallets",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "wallets"
              ]
            },
            "description": "Adds a chain wallet to a vault you already hold key access to. No seed material travels: `vaultId` names the vault (403 if the member behind the key holds no access to it; 404 if unknown or archived). `vaultId` is mutually exclusive with `keyFingerprint`, `encryptedSecretJson` and `vaultName` (400): the vault already defines them. `teamIds` is still accepted, since who can see the wallet is a separate question from which vault signs for it.\n\nOptional `derivationPathPrefix` lets a vault hold a second wallet on the same chain at a different path, e.g. the next BIP44 account m/44'/60'/1'/0; the default prefix is refused with 409 if the vault already has a wallet there. Addresses must sit at `<prefix>/<accountIndex>`.\n\nRequires the `wallets:create` action.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"treasury-eth\",\n  \"chain\": \"ethereum\",\n  \"network\": \"mainnet\",\n  \"vaultId\": \"{{vaultId}}\",\n  \"teamIds\": [1],\n  \"addresses\": [\n    { \"address\": \"0xabc...\", \"derivationPath\": \"m/44'/60'/0'/0/0\", \"accountIndex\": 0, \"label\": \"main\" }\n  ]\n}"
            }
          }
        },
        {
          "name": "List wallets",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/wallets?limit=20",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "wallets"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "20"
                },
                {
                  "key": "chain",
                  "value": "ethereum",
                  "disabled": true,
                  "description": "Filter by chain: ethereum | bsc | polygon | arbitrum | bitcoin | dogecoin | xrp | polkadot | tron | solana | ton"
                },
                {
                  "key": "network",
                  "value": "mainnet",
                  "disabled": true
                },
                {
                  "key": "name",
                  "value": "treasury-eth",
                  "disabled": true,
                  "description": "Exact, case-sensitive name match. Names are unique per chain+network, so name+chain+network returns at most one wallet."
                },
                {
                  "key": "vaultId",
                  "value": "{{vaultId}}",
                  "disabled": true,
                  "description": "Only the wallets inside this vault."
                },
                {
                  "key": "ids",
                  "value": "12,7,3",
                  "disabled": true,
                  "description": "Only these wallets, as a comma-separated id list (at most 100 per call). For a caller that already holds a set of ids and wants the current rows in one request instead of paging the whole list. Scoping is unchanged: an id the key cannot see simply does not come back."
                },
                {
                  "key": "cursor",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Every wallet belongs to a vault: `vaultId` / `vaultName` name it (`keyId` is the same value under its historical name), `teams` lists the teams that can see and use it (empty = owners and admins only), and `derivationPathPrefix` is the account-level path its addresses hang off (each address is `<prefix>/<accountIndex>`).\n\nEach wallet carries an `access` field: `full` when the caller holds a key-access grant (can reveal/sign/send) or `watch_only` when not. Members and viewers always read `watch_only`; an API key reads `full` when the member who created it holds the grant. Computed per request.\n\nWallets also carry `chainInPlan`: `false` when the wallet's chain/network is no longer included in the organisation's plan (a removed chain add-on or a downgrade). The wallet, balances, and history stay readable, but withdrawals, new addresses, and manual sync return 403 until the chain is back on the plan. Check it before preparing a withdrawal."
          }
        },
        {
          "name": "Get wallet",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/wallets/{{walletId}}",
            "description": "Returns the wallet with its vault (`vaultId`, `vaultName`, `key` = { id, name, fingerprint }), its `derivationPathPrefix`, `nextAccountIndex` (the next address index to derive), and the per-caller `access` field (`full` vs `watch_only`, see List wallets), `chainInPlan` (`false` when the chain left the plan; chain-using calls 403 until it's re-enabled), and a `keyAccess` grant (metadata only) when the caller holds the key. The encrypted secret is served only by the Reveal endpoint."
          }
        },
        {
          "name": "Reveal wallet key secret",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/wallets/{{walletId}}/secret",
            "description": "The SDK/CLI call this for you when deriving or signing, and that is how it is meant to be used \u2014 reach for it directly only if you are implementing signing yourself, since unsealing and deriving by hand is easy to get wrong and the mistakes cost funds rather than raising errors.\n\nReturns the caller's own encrypted custody secret (encryptedSecretJson) for this wallet, encrypted to your key and decryptable only on your device. API keys may read it (acting as the member who created the key) when that member holds a copy of the vault's phrase; viewers cannot. Each access is recorded in the activity log.\n\nHanding a copy to someone else is not done here, or anywhere in the API: it is a dashboard ceremony (see the Vaults folder)."
          }
        },
        {
          "name": "List wallet addresses",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/wallets/{{walletId}}/addresses"
          }
        },
        {
          "name": "Generate wallet address",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/wallets/{{walletId}}/addresses",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "wallets",
                "{{walletId}}",
                "addresses"
              ]
            },
            "description": "Derives and registers a receive address on the wallet server-side, and returns it.\n\nNeeds only the API key \u2014 no encryption password and no key material at the caller. The server derives from the wallet's registered **account xpub**, an extended *public* key that reproduces this wallet's addresses and cannot sign. Spending authority is unchanged: withdrawals are still prepared and signed client-side.\n\nOmit `accountIndex` and the server owns the index, so two concurrent calls receive two consecutive addresses rather than racing for one. Send one to pin the derivation index instead \u2014 the use for it is giving one customer the same address on two wallets that share a vault and a derivation prefix, and so an account xpub, since the same index derives the same address on each. An index already registered on that wallet is refused with 409, archived addresses included: nothing is reassigned and no free index is substituted, because the address on a taken index may already belong to somebody else. Allocation stays highest + 1, so pinning a high index moves that wallet's next automatic index above it. Valid indexes run from 0 to 2147483647, BIP32's non-hardened ceiling.\n\n409 if the wallet has not opted into server derivation \u2014 register an `accountXpub` on it first (see *Enable server-side derivation*), or derive locally and register with `PATCH /wallets/:id`. Polkadot is always 409: its `//i` junctions are hard derivation, which a public key cannot do.\n\nRequires the `wallets:generate_address` action.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"label\": \"customer-4471\",\n  \"accountIndex\": 41\n}"
            }
          }
        },
        {
          "name": "Register a client-derived address",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/wallets/{{walletId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "wallets",
                "{{walletId}}"
              ]
            },
            "description": "Registers an address you derived yourself from the wallet's seed. This is what `deriveAddress()` in the SDK, `derive_address()` in the Python SDK and **Add address** in the dashboard send after unsealing the vault locally; it is also the only way to add addresses to a Polkadot wallet, or to any wallet that has not enabled server-side derivation.\n\n`addresses` is additive: the entries you send are created or updated, everything already on the wallet is left alone. Each entry carries the address, its full `derivationPath` and its `accountIndex`, and the path must be exactly the wallet's `derivationPathPrefix` plus that index.\n\nThe server holds the registration to three things, and refuses the whole batch if any entry fails:\n\n- **Key access.** The key's owner must hold key access to the wallet's vault \u2014 registering an address claims it was derived from the seed, which nobody without the seed can do. A role alone is not enough, whatever else the body carries: `403`.\n- **Format.** Every address must be a well-formed address for the wallet's chain and network \u2014 checksum, encoding and network prefix are checked (EIP-55 on EVM, bech32/base58check for the right Bitcoin network, classic `r\u2026` on XRP, SS58 with the network's prefix on Polkadot). A typo or an address from another chain is `400`.\n- **The wallet's own key.** On a wallet with server-side derivation enabled, each address must be the one the registered account xpub derives at that index. Anything else is `400`, and nothing from the batch is stored.\n\nRequires `wallets:generate_address` or `wallets:update` on the wallet, plus `wallets:read` to receive the updated wallet in the response.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"addresses\": [\n    {\n      \"address\": \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\",\n      \"derivationPath\": \"m/44'/60'/0'/0/1\",\n      \"accountIndex\": 1,\n      \"label\": \"customer-4472\"\n    }\n  ]\n}"
            }
          }
        },
        {
          "name": "Enable server-side derivation",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/wallets/{{walletId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "wallets",
                "{{walletId}}"
              ]
            },
            "description": "Registers the wallet's account xpub so the server can derive its later addresses on its own.\n\nThe xpub is the extended **public** key at the wallet's `derivationPathPrefix`, serialized with Bitcoin mainnet version bytes (`xpub...`) whatever the chain. Compute it where the seed is \u2014 `accountXpubFromMnemonic()` in the SDK, `account_xpub_from_mnemonic()` in the Python SDK, or `guveno enable-derivation <wallet>` in the CLI. In the dashboard it is a switch: **Wallet \u2192 Settings \u2192 Address generation**, which computes the key in the browser and sends this same request. An extended *private* key is rejected, never neutered for you.\n\nBefore storing it the server re-derives the addresses already registered on the wallet and requires every one to match, which is what proves the key belongs to this wallet's seed. One mismatch rejects the request with 400 and nothing is stored. A wallet with no registered addresses cannot be verified, so it is refused too.\n\nSend `\"accountXpub\": null` to turn server derivation back off. Requires the `wallets:update` action \u2014 deliberately *not* `wallets:generate_address`, so a key that may use server derivation cannot also enable it.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"accountXpub\": \"xpub6DyUKdwoLWmUJ...\"\n}"
            }
          }
        }
      ]
    },
    {
      "name": "Assets",
      "item": [
        {
          "name": "List assets",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/assets?type=erc20",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "assets"
              ],
              "query": [
                {
                  "key": "chain",
                  "value": "ethereum",
                  "disabled": true,
                  "description": "Filter by chain: ethereum | bsc | polygon | arbitrum | bitcoin | dogecoin | xrp | polkadot | tron | solana | ton"
                },
                {
                  "key": "type",
                  "value": "erc20",
                  "description": "Filter by type: native | erc20 | trc20 | spl | spl2022 | jetton"
                },
                {
                  "key": "enabled",
                  "value": "true",
                  "disabled": true
                }
              ]
            }
          }
        },
        {
          "name": "Get asset",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/assets/{{assetId}}",
            "description": "One asset your organization can see. 404 for an asset it cannot."
          }
        }
      ],
      "description": "Assets your organization can see: the core assets, the Guveno catalog, and tokens your organization added by contract address (`visibility`: core | public | private). Another organization's tokens never appear, and reading one by id returns 404. Changing the list is done in the dashboard."
    },
    {
      "name": "Balances",
      "item": [
        {
          "name": "Wallet balances",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/wallets/{{walletId}}/balances"
          }
        },
        {
          "name": "Wallet balance totals",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/wallets/{{walletId}}/balances/total"
          }
        },
        {
          "name": "Wallet stats",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/wallets/{{walletId}}/stats"
          }
        },
        {
          "name": "Company balance summary",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/company/balances/summary"
          }
        },
        {
          "name": "Estimated prices",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/prices"
          }
        }
      ]
    },
    {
      "name": "Transactions",
      "item": [
        {
          "name": "List transactions",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/transactions?limit=50",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "transactions"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "50"
                },
                {
                  "key": "walletId",
                  "value": "{{walletId}}",
                  "disabled": true
                },
                {
                  "key": "addressId",
                  "value": "{{addressId}}",
                  "disabled": true
                },
                {
                  "key": "chain",
                  "value": "bitcoin",
                  "disabled": true
                },
                {
                  "key": "network",
                  "value": "mainnet",
                  "disabled": true
                },
                {
                  "key": "direction",
                  "value": "incoming",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "confirmed",
                  "disabled": true
                },
                {
                  "key": "asset",
                  "value": "BTC",
                  "description": "Asset symbol; matches any movement. TON still finds GRAM, the TON network's coin.",
                  "disabled": true
                },
                {
                  "key": "search",
                  "value": "",
                  "description": "Substring match on tx hash or any from/to address.",
                  "disabled": true
                },
                {
                  "key": "from",
                  "value": "2026-06-01T00:00:00Z",
                  "description": "ISO-8601 lower bound on createdAt.",
                  "disabled": true
                },
                {
                  "key": "to",
                  "value": "2026-06-30T23:59:59Z",
                  "description": "ISO-8601 upper bound on createdAt.",
                  "disabled": true
                },
                {
                  "key": "amountMin",
                  "value": "0.01",
                  "disabled": true
                },
                {
                  "key": "amountMax",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "marked",
                  "value": "flagged_open",
                  "description": "Restrict to a review list. \"saved\" is your own personal star queue. The flagged views match a flag from any member whose visibility you share: \"flagged\" is any flag, \"flagged_open\" only the ones still waiting on a review, \"flagged_resolved\" only the closed ones. \"assigned\" is the open flags someone asked you to look at.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "disabled": true
                }
              ]
            },
            "description": "Newest first. Every filter is optional and they combine (AND). Each transaction carries `wallet`, the id and name of the wallet it was recorded against; enable `walletId` to list only that wallet's transactions."
          }
        },
        {
          "name": "Get transaction",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/transactions/{{transactionId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "transactions",
                "{{transactionId}}"
              ]
            },
            "description": "One transaction by id, in the same shape as a list item \u2014 including its review marks and its `wallet` (the id and name of the wallet it was recorded against). Use it to follow a link to a transaction a teammate flagged.\n\nXRP transactions carry `destinationTag`: for a deposit, the tag the payment was sent with; for a withdrawal, the tag it was sent to. It is null when there was none, and on every other chain.\n\nTON transactions carry `memo`, the text comment the payment was sent with (deposit) or sent with by us (withdrawal). It is null when there was none, when the payload was not a readable text comment, and on every other chain."
          }
        },
        {
          "name": "Get transaction marks",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/transactions/{{transactionId}}/marks",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "transactions",
                "{{transactionId}}",
                "marks"
              ]
            },
            "description": "Review marks on a transaction \u2014 the star (\"save for later\") / flag layer teams use in the dashboard.\n\nThe two marks differ in audience:\n- saved (star) + its note: PERSONAL unless shared. Your own review queue. Another member's star is never reported to you, and yours is never reported to them, until you set noteShared, which shows your star and its note to everyone who can already see the transaction, with your name.\n- flagged + assignee: SHARED, with the author attached. A flag says \"this needs attention\", so everyone who can already see the transaction sees who raised it and why. A raised flag's note is always shared.\n\nsaved / noteShared / flagged / note at the top level are yours (an API key acts as its creator); `shared` lists every member's flag, and every star and note its author chose to share, with its author.\n\nMarks are organizational only \u2014 they never affect crediting, confirmations or balances. Reading and writing them needs only transactions:read."
          }
        },
        {
          "name": "Set transaction marks",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/transactions/{{transactionId}}/marks",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "transactions",
                "{{transactionId}}",
                "marks"
              ]
            },
            "description": "Sets YOUR OWN marks. Only the fields you send change, so the star, the flag and the note can each be written on their own \u2014 this example raises a flag with a note and leaves the star alone.\n\nSend \"\" or null as the note to clear it. Notes are capped at 1000 characters. The record is removed once no mark is left set, and clearing an absent mark is a 200 no-op.\n\nA note written without a flag is PRIVATE: noteShared is false on a first write and kept thereafter, so leaving it out writes a note only your own key reads back. Send noteShared: true to show your star and its note to the team, with your name; it never changes a raised flag, whose note is always shared.\n\nReview marks on a transaction \u2014 the star (\"save for later\") / flag layer teams use in the dashboard.\n\nThe two marks differ in audience:\n- saved (star) + its note: PERSONAL unless shared. Your own review queue. Another member's star is never reported to you, and yours is never reported to them, until you set noteShared, which shows your star and its note to everyone who can already see the transaction, with your name.\n- flagged + assignee: SHARED, with the author attached. A flag says \"this needs attention\", so everyone who can already see the transaction sees who raised it and why. A raised flag's note is always shared.\n\nsaved / noteShared / flagged / note at the top level are yours (an API key acts as its creator); `shared` lists every member's flag, and every star and note its author chose to share, with its author.\n\nA flag also has a lifecycle: raised, then either resolved (reviewed and closed) or withdrawn. assignToUserId names the one member it is waiting on. They are notified once, in the dashboard and by email, so it requires a raised flag and a member who can already see the transaction \u2014 anyone else is refused. Send null to clear it. A flag with nobody named notifies nobody.\n\nClosing a flag is a separate request (Resolve transaction flag): the person who reviews a flag is usually not the one who raised it.\n\nMarks are organizational only \u2014 they never affect crediting, confirmations or balances. Reading and writing them needs only transactions:read.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"flagged\": true,\n  \"note\": \"unexpected fee, review with finance\",\n  \"assignToUserId\": 8\n}"
            }
          }
        },
        {
          "name": "Resolve transaction flag",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/transactions/{{transactionId}}/marks/resolve",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "transactions",
                "{{transactionId}}",
                "marks",
                "resolve"
              ]
            },
            "description": "Closes a flag as reviewed, or re-opens one.\n\nSeparate from Set transaction marks because it acts on a MEMBER's flag rather than on your own record: the person who reviews a flag is usually not the one who raised it. Pass raisedByUserId to close someone else's flag, or omit it for your own. The flag keeps naming who raised it and records who reviewed it, so \"has anyone looked at this\" has an answer.\n\nSend {\"resolved\": false} to put a resolved flag back in the queue. Resolving one that is already resolved changes nothing and notifies nobody a second time, so a retry is safe. Withdrawing a flag (flagged: false on Set transaction marks) clears its resolution and assignee with it.\n\nNeeds only transactions:read, like raising a flag: the roles that most want to review things are read-only by design.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"raisedByUserId\": 3,\n  \"resolved\": true\n}"
            }
          }
        },
        {
          "name": "Transaction mark summary",
          "request": {
            "method": "GET",
            "url": {
              "raw": "{{baseUrl}}/transactions/marks/summary",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "transactions",
                "marks",
                "summary"
              ]
            },
            "description": "Counts for the review lists: `saved` is how many you saved, `flagged` how many are flagged by anyone whose visibility you share, `flaggedOpen` how many of those are still waiting on a review, and `assignedToMe` the open flags someone asked you to look at. Page through any of them with ?marked= on List transactions."
          }
        }
      ]
    },
    {
      "name": "Withdrawals",
      "description": "Two-step flow: prepare an unsigned transaction, sign it locally (SDK/CLI), then broadcast. Both write calls need an Idempotency-Key.",
      "item": [
        {
          "name": "Prepare withdrawal",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "url": "{{baseUrl}}/withdrawals/prepare",
            "description": "Choose the source with EITHER walletId OR addressId (exactly one).\n\n- walletId: auto-select. The server picks a source with enough available balance. Account chains (Ethereum/XRP/Polkadot/TON/...) pick one address that covers the amount; Bitcoin and Dogecoin aggregate UTXOs across the wallet and return change to a wallet-owned address. Fails 422 on account chains if no single address covers the amount. Requires the wallet's autoWithdrawal setting to be on (the default); a walletId-only prepare against a wallet with autoWithdrawal=false is rejected with 400.\n- addressId: advanced. Send from one specific address. Bitcoin and Dogecoin can instead pass sourceAddressIds (an array) to restrict aggregation to a subset. On Dogecoin each input in the signing payload also carries prevTxHex, its full previous transaction, which the signer verifies and reads the input value from. Always allowed, including when the wallet's autoWithdrawal is off.\n\nThis example uses auto-select; swap the body for { \"addressId\": {{addressId}}, ... } to pin a source.\n\nReplaying this call with a withdrawal's original Idempotency-Key returns the same withdrawal and a fresh signing payload \u2014 UNLESS that withdrawal already has signed bytes committed, in which case it returns 409 rather than issue a payload that would be signed at a new nonce. Preparing from an address whose previous send is unresolved also returns 409 until that send is reconciled.\n\nXRP: pass `destinationTag`, an integer from 0 to 4294967295, when the recipient needs one (exchanges usually do). It is carried into the signed Payment, and a signed transaction whose tag does not match is refused at broadcast. It is accepted only on XRP: sending one on any other chain is a 400, since nothing there could carry it.\n\nTON: pass `memo`, the text comment the recipient reads, when they need one (exchanges usually do). 1 to 120 bytes of UTF-8, no control characters (no newlines or tabs); a longer memo is refused, not split. It goes into the signed message, inside the token transfer for a jetton, and a signed message whose memo does not match byte for byte is refused at broadcast. It is accepted only on TON: sending one on any other chain is a 400. TON destinations must be the user-friendly form for the network (EQ\u2026/UQ\u2026 on mainnet, kQ\u2026/0Q\u2026 on testnet); the bounce flag of the address you paste is kept, and the raw 0:\u2026 form is refused. Jetton sends need GRAM in the source address for the network fee plus a 0.05 GRAM attachment, most of which comes back.\n\nSpending policies: if one of the organization's policies refuses this withdrawal the answer is 403 with `code` `policy_denied` (not allowed) or `policy_approval_required` (propose it as a withdrawal request instead), plus `policyIds`. Nothing is reserved.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"walletId\": {{walletId}},\n  \"assetId\": {{assetId}},\n  \"amount\": \"0.25\",\n  \"toAddress\": \"0xRecipient...\"\n}"
            }
          }
        },
        {
          "name": "Prepare withdrawal (TON, with memo)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "url": "{{baseUrl}}/withdrawals/prepare",
            "description": "A TON payout to an exchange that attributes deposits by memo. `memo` is TON only: 1 to 120 bytes of UTF-8 with no control characters, refused on every other chain. `toAddress` must be the user-friendly form for the network; its bounce flag is kept and the raw 0:\u2026 form is refused. For a jetton (such as USDT), use its asset id: the memo travels inside the token transfer, and the source address needs GRAM for the fee plus a 0.05 GRAM attachment, most of which comes back.\n\nEverything else works as in Prepare withdrawal.\n\nSpending policies: if one of the organization's policies refuses this withdrawal the answer is 403 with `code` `policy_denied` (not allowed) or `policy_approval_required` (propose it as a withdrawal request instead), plus `policyIds`. Nothing is reserved.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"walletId\": {{walletId}},\n  \"assetId\": {{assetId}},\n  \"amount\": \"40\",\n  \"toAddress\": \"UQRecipient...\",\n  \"memo\": \"4471203\"\n}"
            }
          }
        },
        {
          "name": "Broadcast withdrawal",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}"
              }
            ],
            "url": "{{baseUrl}}/withdrawals",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"withdrawalId\": {{withdrawalId}},\n  \"signedRawTx\": \"0x02f8...\"\n}"
            },
            "description": "Submits the signed transaction. Guveno records your signed bytes, and the hash they will have, BEFORE handing them to a node, and submits them exactly once.\n\nRead the failures carefully \u2014 this is the one call whose failure does not mean \"nothing happened\":\n\n- 200: accepted. The withdrawal moves to `broadcast`.\n- 400: the node refused it on its merits (usually the source cannot fund gas). Nothing was sent, the withdrawal stays `prepared`, and you can fix the problem and broadcast again.\n- 409: this withdrawal already has signed bytes committed and you sent different ones. Resend the identical signedRawTx, or reconcile the committed transaction on-chain.\n- 502: OUTCOME UNKNOWN. The transaction may be on the network. The body carries the committed `txHash`. Look it up on-chain, or call this endpoint again with the IDENTICAL signedRawTx (the same bytes are the same transaction, so that is not a second payment).\n\nNever sign a replacement after a 502. On an account chain that is a new nonce, and if the first transaction landed you have paid the recipient twice. While a send is unresolved, preparing any new withdrawal from the same address is refused with 409."
          }
        },
        {
          "name": "List withdrawals",
          "request": {
            "method": "GET",
            "description": "Withdrawals are returned newest-first. Set the page size with `limit` (default 100, max 200) and pass `pageInfo.nextCursor` from the response back as `cursor` to fetch the next page; a null cursor means the last page.\n\nEach withdrawal carries `sourceAddresses`: every address it spends from, each once, with the address `addressId` points to first. Account chains have exactly one; a Bitcoin or Dogecoin withdrawal also lists every address whose coins it spends. The set is fixed at prepare. The withdrawal.broadcast, withdrawal.confirmed and withdrawal.rejected webhooks carry the same `sourceAddresses` next to `fromAddress`.",
            "url": {
              "raw": "{{baseUrl}}/withdrawals?limit=50",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "withdrawals"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "50"
                },
                {
                  "key": "walletId",
                  "value": "{{walletId}}",
                  "disabled": true
                },
                {
                  "key": "addressId",
                  "value": "{{addressId}}",
                  "disabled": true
                },
                {
                  "key": "chain",
                  "value": "ethereum",
                  "disabled": true
                },
                {
                  "key": "network",
                  "value": "mainnet",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "broadcast",
                  "description": "prepared, broadcast, confirmed or rejected.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "pageInfo.nextCursor from the previous page.",
                  "disabled": true
                }
              ]
            }
          }
        },
        {
          "name": "Get withdrawal",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/withdrawals/{{withdrawalId}}",
            "description": "Each withdrawal carries `sourceAddresses`: every address it spends from, each once, with the address `addressId` points to first. Account chains have exactly one; a Bitcoin or Dogecoin withdrawal also lists every address whose coins it spends. The set is fixed at prepare. The withdrawal.broadcast, withdrawal.confirmed and withdrawal.rejected webhooks carry the same `sourceAddresses` next to `fromAddress`."
          }
        }
      ]
    },
    {
      "name": "Withdrawal requests",
      "description": "A proposed payout that a person has to approve before anything is signed. Part of the Pro and Enterprise plans: on other plans creating a request answers 403 (reading and declining are never gated).\n\nThis is how an integration asks for a withdrawal while holding no spending authority. The key needs the `withdrawals:request` action on the wallet \u2014 not `withdrawals:create`, which is the signing action the approver spends. Creating a request moves no funds and signs nothing \u2014 it records an intent. An approver reviews it and signs with their own key, so a leaked API key cannot move funds on its own.\n\nApproving and declining happen in the dashboard: the approver reviews the request and signs it in their browser. There is no route an API key alone can reach that moves funds or decides a request.",
      "item": [
        {
          "name": "Propose a withdrawal",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/withdrawal-requests",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "withdrawal-requests"
              ]
            },
            "description": "Requires the `withdrawals:request` action on the wallet. That is a different grant from `withdrawals:create`: a key that can only propose holds no spending authority, and a key granted only `withdrawals:create` cannot propose at all.\n\nRecords a proposed payout for a person to approve.\n\nIdempotent on `idempotencyKey`: a repeat with the same key returns the original request, so a caller that already debited a user and then lost the response can retry without proposing a second payout. The same key with different parameters is a `409`.\n\n`approverUserId` asks a specific member to review it \u2014 they are emailed and notified. They must be a member whose role can approve *and* who holds key access on the wallet, since approving means signing; anyone else is refused. It is advisory: any other authorized member can still approve, so an absent approver cannot strand a payout.\n\n`expiresInSeconds` is 5 minutes to 30 days, 7 days by default. An unanswered request expires rather than lingering as a standing authorization to move funds.\n\nXRP: `destinationTag` (an integer from 0 to 4294967295) is kept on the request exactly as proposed, and it is what the approver signs. It is refused on any other chain.\n\nTON: `memo` (1 to 120 bytes of UTF-8, no control characters) is kept on the request the same way and signed exactly as proposed. It is refused on any other chain.\n\nRequires the `withdrawals:create` action.\n\nSpending policies are checked here too: a payout a policy forbids is refused with 403 `code: policy_denied`. One a policy wants several people to approve is created with `policyRequirements` listing each policy, how many approvals it needs and from which roles.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"walletId\": 12,\n  \"assetId\": 3,\n  \"toAddress\": \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\",\n  \"amount\": \"1.5\",\n  \"idempotencyKey\": \"exchange-withdrawal-991\",\n  \"reference\": \"exchange tx 991\",\n  \"approverUserId\": 5\n}"
            }
          }
        },
        {
          "name": "List withdrawal requests",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/withdrawal-requests?status=pending_approval",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "withdrawal-requests"
              ]
            },
            "description": "Query params: `status` (`pending_approval`, `approved`, `rejected`, `expired`), `walletId`, `limit`, `cursor`. Newest first.\n\n`policyRequirements` lists the sign-offs the organization's spending policies ask for (empty means the usual single approver), and `approvals` lists who has signed off so far. The member who finally signs counts as the last approval; the proposer never counts."
          }
        },
        {
          "name": "Get a withdrawal request",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/withdrawal-requests/{{withdrawalRequestId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "withdrawal-requests",
                "{{withdrawalRequestId}}"
              ]
            },
            "description": "Poll this to learn the outcome.\n\n`approved` carries `withdrawalId` \u2014 fetch that withdrawal for the transaction hash and confirmations. `rejected` means a person declined it (`declineReason` says why); `expired` means nobody acted in time. Neither produces a withdrawal and neither is retried, so a caller that still wants the payout proposes a new request under a new key.\n\nThere is no webhook for a decline: `withdrawal.broadcast` fires when an approval goes out, but a declined request never becomes a withdrawal. Poll this endpoint for that case.\n\n`policyRequirements` lists the sign-offs the organization's spending policies ask for (empty means the usual single approver), and `approvals` lists who has signed off so far. The member who finally signs counts as the last approval; the proposer never counts."
          }
        }
      ]
    },
    {
      "name": "Webhooks",
      "item": [
        {
          "name": "Create webhook",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/webhooks",
            "description": "Owner/admin/tech only. Optionally pass your own \"signingSecret\" (16\u2013256 chars); omit it and one is generated. The secret is returned only once, in this response. Pass \"walletIds\" (array of wallet ids) to scope the webhook to specific wallets; omit it or send an empty array to receive events for all wallets.\n\nDeposit events on XRP carry `destinationTag`: the tag the payment was sent with, or null when it had none. Use it to attribute a deposit to a customer when several share one address. For a tagged payment, `toAddress` also reads `address:tag`.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"type\": \"api\",\n  \"config\": { \"url\": \"https://example.com/guveno\" },\n  \"events\": [\"*\"],\n  \"walletIds\": []\n}"
            }
          }
        },
        {
          "name": "List webhooks",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/webhooks"
          }
        },
        {
          "name": "Update webhook",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/webhooks/{{webhookId}}",
            "description": "Owner/admin/tech only. Send only the fields to change: \"config\" (replaces the stored config whole), \"events\", \"walletIds\" (empty array = all wallets, only for a caller who sees every wallet) and \"enabled\". An empty body is refused. The type is fixed at creation, and the signing secret is neither changed nor returned. Pending deliveries go to the new destination.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"config\": { \"url\": \"https://example.com/guveno-v2\" },\n  \"events\": [\"deposit.confirmed\"]\n}"
            }
          }
        },
        {
          "name": "Rotate webhook secret",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/webhooks/{{webhookId}}/rotate-secret",
            "description": "Owner/admin/tech only. Send a \"signingSecret\" to set your own, or an empty body to auto-generate. The new secret is returned once and signs deliveries immediately.",
            "body": {
              "mode": "raw",
              "raw": "{}"
            }
          }
        },
        {
          "name": "Webhook deliveries",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/webhooks/{{webhookId}}/deliveries"
          }
        },
        {
          "name": "Webhook delivery",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/webhooks/{{webhookId}}/deliveries/{{deliveryId}}",
            "description": "One delivery in full: the exact JSON body we posted \u2014 the bytes the x-guveno-signature header signs \u2014 and the reply your endpoint gave, truncated to 2KB. Both are left out of the delivery list, which stays small enough to poll."
          }
        },
        {
          "name": "Delete webhook",
          "request": {
            "method": "DELETE",
            "url": "{{baseUrl}}/webhooks/{{webhookId}}"
          }
        }
      ]
    },
    {
      "name": "Network status",
      "item": [
        {
          "name": "Chain sync status",
          "request": {
            "method": "GET",
            "url": "{{baseUrl}}/sync/status"
          }
        },
        {
          "name": "Re-scan an address",
          "request": {
            "method": "POST",
            "url": "{{baseUrl}}/addresses/{{addressId}}/sync",
            "description": "Re-reads this address's native balance from the chain now and nudges the worker to re-scan for deposits. Returns 202 `{ \"accepted\": true }`.\n\nEach address can be refreshed once every 5 minutes. A repeat inside that window returns 429 with a `Retry-After` header; wait that long rather than retrying."
          }
        }
      ]
    }
  ]
}
