For the complete documentation index, see llms.txt. This page is also available as Markdown.

Enterprise API

The SSP Enterprise API gives your own systems programmatic access to your organization's vaults, balances, transactions, proposals, and portfolio analytics. Use it to feed an internal dashboard, reconcile balances, monitor proposal status, or export data into your own tooling β€” without logging into the app. Read access is read-only; a single optional write scope lets automation create a proposal that still requires your normal signatures to execute.

A key can never move funds. The read scopes are GET-only. The write scopes only ever queue or configure β€” never sign, approve, or broadcast: proposals:write can create a pending proposal, policies:write can adjust a vault's spending rules, vaults:write can create/configure vaults, and contacts:write edits a labelling address book. Every proposal, however it was created, still requires the vault's M-of-N device signatures (each signed by both SSP Wallet and SSP Key) to execute. So a leaked key can, at most, propose a payment your signers must then approve in the app β€” it can never move money or change ownership. This is the core safety property of the API, enforced by construction.

Base URL

https://relay.sspwallet.com/v1/api

Authentication

The Enterprise API authenticates with a bearer API key. Send it in the Authorization header on every request:

Authorization: Bearer ssp_live_<your key>

A key looks like ssp_live_ followed by a long random string, for example:

ssp_live_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8s9T0u1V2

If the header is missing, malformed, points to a revoked or expired key, or lacks the scope required by the endpoint, the request is rejected β€” see Errors.

The organization is derived from the key

An API key belongs to exactly one organization, and that organization is taken from the key itself β€” never from the URL or any request parameter. A key issued for organization A can only ever read organization A's data; it can never read, reference, or even discover another organization. There is no organization ID to pass, and no way to widen a key's reach by changing the request.

Creating a key

API keys are created and managed inside the SSP Enterprise app, under Settings β†’ Developers β†’ API Keys.

  • Only owners and admins of the organization can create or revoke API keys. Members and viewers cannot.

  • When you create a key you choose a name (for your own reference, e.g. "Grafana read-only") and select which scopes it should have.

  • The full key is shown only once, at creation time. SSP stores only a SHA-256 hash of it and can never show it again. Copy it into your secret manager immediately. If you lose it, revoke it and create a new one.

  • For identification, the app displays only a short prefix of the key (e.g. ssp_live_a1b2) alongside its name, scopes, status, and last-used time.

Revoking a key

From the same Settings β†’ Developers β†’ API Keys screen, an owner or admin can revoke any key. Revocation is immediate β€” the key is checked against its status on every request, so the next call made with a revoked key fails with 401. Revocation cannot be undone; create a new key if you need access again.

Keep your keys secret. Treat ssp_live_... like a password: never commit it to source control, embed it in a frontend bundle, or paste it into a browser. A leaked key can read one organization's data and, if it has the proposals:write scope, create a pending proposal β€” but it can never sign, move funds, or change settings, because execution always requires your vault's device signatures.

Scopes

Each key carries a set of scopes. Every endpoint requires one specific scope; if the key doesn't have it, the request fails with 403. Grant a key only the scopes it actually needs.

Scope
Grants read access to

org:read

Your organization's profile

vaults:read

The list of vaults and individual vault details

balances:read

Per-vault balances

transactions:read

Per-vault transaction history

proposals:read

Per-vault transaction proposals

analytics:read

Aggregated portfolio analytics

contacts:read

Your organization's saved address book

policies:read

Vault & org policies, policy rules, approval groups, and policy templates

Write scope
Grants

proposals:write

Create or cancel a pending proposal on a vault β€” never signs or moves funds

contacts:write

Manage the organization address book (create / update / delete contacts)

policies:write

Update a vault's spending policy (limits, whitelist, rules) β€” a control, not a fund movement

vaults:write

Create and configure vaults, and manage vault tag definitions β€” never signs or moves funds

The read scopes are read-only. The write scopes never sign, approve, broadcast, or move funds: proposals:write can only create or cancel a pending proposal (which still requires your vault's device signatures to execute), contacts:write only edits a labelling address book that has no effect on policy, policies:write only tightens or loosens a vault's spending rules, and vaults:write only creates or configures vaults (a vault created this way holds no funds until you fund it, and still needs its M-of-N devices to spend). None can move money or approve a proposal. A policies:write key's creator must be an admin of the vault it targets; vaults:write requires an organization admin. Creating a key with any write scope requires the Pro plan or higher.

Response format

Every response uses the standard SSP envelope:

On error, status is "error" and data describes the problem β€” see Errors.

Pagination

List endpoints (vaults, transactions, proposals) use cursor-based pagination:

  • limit β€” how many items to return per page. The default is 20 and the maximum is 100; larger values are clamped to 100.

  • cursor β€” an opaque token. Omit it on the first request; pass the nextCursor from a response to fetch the next page.

Each paginated response includes a pagination object:

When hasMore is false, nextCursor is null and you've reached the end. Treat the cursor as opaque β€” its contents may change, so don't parse or construct it yourself.

Example: fetch the next page of transactions:

Rate limits

Requests are rate limited per API key (with an additional global per-IP limit). The read API allows roughly 60 requests per minute per key, with a short burst allowance above that. If you exceed the limit, you receive a 429 response; back off and retry after a short delay. Batch and cache where you can rather than polling tightly.

Endpoints

All endpoints are GET and require the Authorization: Bearer header. Path parameters such as :vaultId and :proposalId are the IDs returned by the list endpoints.


Get organization

Scope: org:read

Returns the profile of the organization the key belongs to.


List vaults

Scope: vaults:read

Lists the vaults in your organization. Paginated.


Get a vault

Scope: vaults:read

Returns full details for a single vault in your organization.


Get vault balances

Scope: balances:read

Returns the current balances for a vault.


List vault transactions

Scope: transactions:read

Lists the transaction history for a vault, newest first. Paginated.


List vault proposals

Scope: proposals:read

Lists transaction proposals for a vault, newest first. Paginated.


Get a proposal

Scope: proposals:read

Returns full details for a single proposal, including which signers have signed.

Proposal details contain only the metadata already visible to your team inside the app. They never include private keys, raw signatures, nonces, xpubs, or witness scripts.


Get portfolio analytics

Scope: analytics:read

Returns aggregated portfolio analytics across all vaults in your organization.


Read policy configuration

Read back the policy configuration that the policies:write endpoints manage β€” useful for auditing, drift detection, or syncing config into your own systems.

Scope: policies:read. Org-scoped (the key determines the organization); no signing material is ever returned. Each mirrors the shape written by the corresponding policies:write endpoint, so config round-trips.


Create a proposal

Scope: proposals:write Β· Requires the Pro plan or higher.

Creates a pending transaction proposal on a vault β€” the same object the app creates when a signer proposes a payment. The proposal is attributed to the wkIdentity that created the API key, who must be a signer or admin on the target vault. It runs through your organization's full policy engine (spending limits, whitelists, approval workflows, IP/geo rules) exactly like an app-created proposal.

This endpoint only creates a proposal. It never signs, approves, or broadcasts. The returned proposal has status: "pending" and an empty signatures list; it executes only once your vault's M-of-N signers approve it in SSP Wallet + SSP Key. A write key can propose a payment, never send one.

Body:

Field
Type
Notes

recipients

array (required)

One or more { "address": "...", "amount": "1.5" }. amount is a decimal string in the chain's main unit.

memo

string

Optional note stored with the proposal.

fee, feePerByte, gasPrice, …

β€”

Optional chain-specific fee controls (same options as the app).

tokenContract, tokenSymbol, tokenDecimals

β€”

For ERC-20 transfers (EVM only); omit for native currency.

The vault's chain is taken from the vault itself β€” you don't pass it.

If the key's creator isn't a vault signer, a policy blocks the transfer, funds are insufficient, or the payload is invalid, the response is still HTTP 200 but carries data.success: false with an errorCode such as NOT_SIGNER, POLICY_BLOCKED, INSUFFICIENT_FUNDS, or INVALID_RECIPIENTS. Write calls are rate-limited to 30 requests per minute per key.


Cancel a proposal

Scope: proposals:write

Cancels a pending proposal β€” the same as withdrawing it in the app. The key's creator must be the proposer or a vault admin. Cancelling only sets the proposal's status to cancelled; it moves no funds and cannot cancel a proposal that has already been signed and broadcast. Returns the updated proposal.


Create a vault

Scope: vaults:write Β· Requires the Pro plan or higher. Creates a new vault in your organization. The key's creator must be an organization admin or owner. A vault created here holds no funds until you fund it, and spending always requires its M-of-N device signatures β€” creating one never moves money. Returns the new vault (same redacted shape as the read API).

Update a vault

Scope: vaults:write. Updates a vault's configuration (e.g. name, description, tags). Org admin/owner only. Returns the updated vault.

Vault tags

Reusable tag definitions you can attach to vaults for organization and filtering.

Scope: vaults:write. Org admin/owner only. Create takes { "name": "...", "description": "...", "color": "..." } (color optional).


Update a vault policy

Scope: policies:write Β· Requires the Pro plan or higher.

Updates the vault's spending policy β€” transaction/aggregate limits, per-token limits, whitelist mode, time-lock, approval overrides, and other policy sections. A policy is a control, not a fund movement: changing it never signs, approves, or broadcasts anything, and existing proposals still require the vault's M-of-N device signatures to execute. The key's creator must be an admin of the target vault (org owner/admin, or a vault-level admin); otherwise the call returns INSUFFICIENT_ROLE.

The request body contains only the policy sections you want to change; omitted sections are left unchanged. Each section is validated server-side (for example, a vault limit may not be looser than the org default). Returns the updated policy.


Policy rules

Policy rules are the programmable, ordered side of a vault's spending policy β€” each rule matches conditions on a proposal and applies an action (allow, block, require approval, time-lock). This is the "policy-as-code" surface: define your controls in your own systems and push them via the API.

Scope: policies:write Β· Requires the Pro plan or higher. Rules are a control: they gate or route proposals, they never sign or move funds. The key's creator must be an admin of the target vault (org owner/admin, or a vault-level admin); otherwise the call returns INSUFFICIENT_ROLE. Each rule is validated server-side.

Reorder takes the full ordered list of rule ids: { "ruleIds": ["rule_c", "rule_a", "rule_b"] }.


Vault whitelist

A vault's allowed-destination list and its enforcement mode. The whitelist is a control on where funds may go; editing it never signs or moves funds.

Scope: policies:write. The key's creator must be an admin of the target vault. Mode takes { "mode": "disabled" | "warn" | "enforce" }. Add takes { "address": "...", "label": "...", "chain": "..." } (label/chain optional). Remove takes { "address": "..." }. Each returns the updated policy.


Update the organization policy

Scope: policies:write Β· Requires the Pro plan or higher. Updates the organization-wide default policy that every vault inherits β€” individual vaults may only make their policy stricter, never looser. The key's creator must be an organization owner or admin; otherwise the call returns INSUFFICIENT_ROLE. Body contains only the sections you want to change; returns the updated org policy.


Organization policy rules

The org-wide rule set every vault inherits β€” same shape as vault policy rules, but applied at the organization level.

Scope: policies:write. The key's creator must be an organization owner or admin. Bodies match the vault policy-rule endpoints; reorder takes { "ruleIds": [...] }.


Organization per-chain policy

A stricter policy override for a specific chain (for example, tighter BTC limits than your org default).

Scope: policies:write. Org owner/admin only. :chain is the chain identifier (e.g. btc, eth). Returns the updated org policy.


Approval groups

Named signer quorums (e.g. "Finance β€” 2 of 3") that policy rules reference to require multi-party approval. Managing a group defines who must approve; it never signs or moves funds.

Scope: policies:write. The key's creator must be an organization owner or admin. Body: { "name": "...", "description": "...", "members": ["wkIdentity", ...], "requiredApprovals": 2 } (description optional). Returns the created/updated group. (Listing groups will arrive with a future policies:read scope.)


Apply a policy template

Scope: policies:write Β· Requires the Pro plan or higher. Materializes a built-in policy template (a curated set of rules, and optionally some flat policy fields) onto a vault in one call. The key's creator must be an admin of the vault. Body: { "templateId": "..." }. Returns the created rules and any flat fields applied.


Contacts (address book)

Your organization's saved recipient address book. Contacts are a convenience/labelling layer only β€” they are not whitelists and have no effect on policy enforcement or which addresses a proposal may pay. contacts:read lists them; contacts:write creates, updates, and deletes them.

The list accepts optional chain, search, limit, and skip query parameters. Create body: { "chain": "btc", "name": "Vendor Inc", "address": "bc1q...", "notes": "optional" }; update accepts any of name, address, notes.

Errors

Errors use the standard SSP envelope, with a machine-readable name and a human-readable message:

HTTP status

name

Meaning

400

BAD_REQUEST

Malformed request β€” for example an invalid cursor or limit.

401

UNAUTHORIZED

Missing, malformed, revoked, or expired API key.

403

FORBIDDEN

The key is valid but lacks the scope this endpoint requires.

404

NOT_FOUND

The requested vault or proposal doesn't exist in your organization. (A key can only ever see its own organization, so resources in other organizations also appear as 404.)

429

RATE_LIMITED

You've exceeded the rate limit β€” back off and retry.

500

INTERNAL_ERROR

Something went wrong on our side.

Frequently asked

Can I create or sign a transaction with an API key? A key with the proposals:write scope can create a pending proposal, but it can never sign one. Signing β€” and therefore actually moving funds β€” always happens in SSP Wallet + SSP Key with your vault's M-of-N devices. A read-only key can't even create a proposal. So no API key can move funds or change a setting; at most a write key can queue a payment for your signers to approve.

Can one key read multiple organizations? No. A key is bound to a single organization, derived from the key itself. To read another organization, create a key from inside that organization.

I lost my key β€” can I recover it? No. Keys are shown once and only a hash is stored. Revoke the lost key and create a new one.

Who can create keys? Only owners and admins of the organization, from Settings β†’ Developers β†’ API Keys.

Last updated