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:writecan create a pending proposal,policies:writecan adjust a vault's spending rules,vaults:writecan create/configure vaults, andcontacts:writeedits 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/apiAuthentication
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_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8s9T0u1V2If 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.
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
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 thenextCursorfrom 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:
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