subcent

API Reference

The Subcent REST API gives you programmatic access to vaults, agents, payments, policies, escrows, merchants, and webhooks. All endpoints are JSON-based and require Bearer token authentication.

Base URL#

https://api.subcent.io/v1

For testnet:

https://testnet-api.subcent.io/v1

Authentication#

Every request must include an Authorization header with a valid API key:

Authorization: Bearer <token>

There are three token types:

| Prefix | Scope | Use Case | |---|---|---| | sc_live_ | Full account access (mainnet) | Server-side integrations | | sc_test_ | Full account access (testnet) | Development and testing | | sc_agent_ | Single vault, payment-only | Issued to AI agents |

Request Format#

All request bodies must be JSON with the Content-Type: application/json header. String amounts are in decimal USDC (e.g., "25.00").

Response Format#

Successful responses return JSON with a 2xx status code. The shape varies by endpoint and is documented on each endpoint page.

Error Response Format#

All errors return a consistent JSON structure:

{
  "error": "error_code_string",
  "message": "Human-readable description of what went wrong"
}

Error Codes#

The following error codes may be returned by any endpoint:

| Error Code | HTTP Status | Description | |---|---|---| | vault_not_found | 404 | The specified vault does not exist | | vault_frozen | 403 | The vault is frozen and cannot process transactions | | insufficient_balance | 400 | The vault does not have enough USDC to cover the payment | | agent_not_authorized | 403 | The agent is not authorized for this vault | | agent_revoked | 403 | The agent's access has been revoked | | policy_violation | 400 | The payment request violates the active spending policy | | policy_not_found | 404 | No policy found for the specified ID or agent | | merchant_not_found | 404 | The specified merchant does not exist | | merchant_suspended | 403 | The merchant account is suspended | | approval_timeout | 408 | The approval request timed out without a decision | | escrow_expired | 400 | The escrow has passed its expiration time | | escrow_already_released | 400 | The escrow funds have already been released | | escrow_not_found | 404 | The specified escrow does not exist | | payment_not_found | 404 | The specified payment does not exist | | webhook_not_found | 404 | The specified webhook does not exist | | invalid_state | 400 | The resource is in a state that does not allow this operation | | invalid_policy_proof | 400 | The on-chain policy proof is invalid or tampered | | rate_limit_exceeded | 429 | Too many requests -- slow down | | chain_error | 502 | An error occurred communicating with the blockchain | | internal_error | 500 | An unexpected internal server error |

Rate Limiting#

The API enforces a rate limit of 100 requests per minute per API key. When exceeded, the API returns a 429 status with the rate_limit_exceeded error code.

Rate limit headers are included on every response:

| Header | Description | |---|---| | X-RateLimit-Limit | Maximum requests per window (100) | | X-RateLimit-Remaining | Requests remaining in current window | | X-RateLimit-Reset | Unix timestamp when the window resets |

Pagination#

List endpoints use cursor-based pagination. The maximum page size is 200 items.

Query Parameters#

| Parameter | Type | Default | Description | |---|---|---|---| | limit | integer | 50 | Number of items to return (max 200) | | cursor | string | -- | Cursor from a previous response to fetch the next page |

Response Shape#

{
  "payments": [...],
  "has_more": true
}

When has_more is true, take the last item's ID and pass it as the cursor parameter to retrieve the next page.

Idempotency#

For POST endpoints that create resources, you can pass an Idempotency-Key header to safely retry requests without creating duplicates:

Idempotency-Key: your-unique-key-here

Keys expire after 24 hours.

API Endpoints#

Vaults#

| Method | Path | Description | |---|---|---| | POST | /v1/vaults | Create a new vault | | GET | /v1/vaults/:id | Get vault details | | POST | /v1/vaults/:id/freeze | Freeze a vault | | POST | /v1/vaults/:id/unfreeze | Unfreeze a vault |

Payments#

| Method | Path | Description | |---|---|---| | POST | /v1/payments/request | Request a payment | | GET | /v1/payments/:id | Get payment details | | GET | /v1/payments | List payments | | POST | /v1/payments/:id/approve | Approve a pending payment | | POST | /v1/payments/:id/reject | Reject a pending payment |

Agents#

| Method | Path | Description | |---|---|---| | POST | /v1/agents | Register a new agent | | DELETE | /v1/agents/:id | Revoke an agent |

Policies#

| Method | Path | Description | |---|---|---| | POST | /v1/policies | Create a policy | | GET | /v1/policies/:id | Get a policy | | PUT | /v1/policies/:id | Update a policy |

Escrows#

| Method | Path | Description | |---|---|---| | POST | /v1/escrows | Create an escrow | | GET | /v1/escrows/:id | Get escrow details | | GET | /v1/vaults/:id/escrows | List escrows for a vault | | POST | /v1/escrows/:id/release | Release escrow funds | | POST | /v1/escrows/:id/refund | Refund escrow funds | | POST | /v1/escrows/:id/dispute | Dispute an escrow |

Merchants#

| Method | Path | Description | |---|---|---| | POST | /v1/merchants/register | Register a merchant | | GET | /v1/merchants/:id | Get merchant details |

Webhooks#

| Method | Path | Description | |---|---|---| | POST | /v1/webhooks | Create a webhook | | GET | /v1/webhooks | List webhooks | | DELETE | /v1/webhooks/:id | Delete a webhook |