Payments API
Payments are the core of Subcent. When an agent requests a payment, the policy engine evaluates it in real time and returns one of three outcomes: completed (auto-approved and settled on-chain), pending_approval (requires human review), or rejected (policy violation).
Request Payment#
/v1/payments/requestSubmit a payment request from an agent to a merchant.
Request Body#
| Field | Type | Required | Description |
|---|---|---|---|
| agent_id | string | Yes | The agent making the payment |
| merchant_id | string | Yes | The merchant receiving the payment |
| amount | string | Yes | Payment amount in decimal USDC (e.g., "25.00") |
| currency | string | No | Currency code. Currently only "USDC" is supported (default) |
| description | string | No | Human-readable description of the payment |
| category | string | No | Spending category (e.g., "groceries", "electronics") |
| metadata | object | No | Arbitrary key-value data attached to the payment |
Standard Categories#
The following categories are recognized by the policy engine:
groceries, household, electronics, clothing, health, beauty, books, entertainment, api_services, data_services, computing, storage, transportation, food_delivery, subscription
Example Request#
{
"agent_id": "agt_550e8400-e29b-41d4-a716-446655440000",
"merchant_id": "mrc_660e8400-e29b-41d4-a716-446655440000",
"amount": "25.00",
"currency": "USDC",
"description": "Weekly grocery order",
"category": "groceries",
"metadata": {
"order_id": "ord_12345",
"items_count": 8
}
}
Response (Auto-Approved)#
{
"payment_id": "pay_770e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"amount": "25.00",
"currency": "USDC",
"merchant_id": "mrc_660e8400-e29b-41d4-a716-446655440000",
"vault_id": "550e8400-e29b-41d4-a716-446655440000",
"agent_id": "agt_550e8400-e29b-41d4-a716-446655440000",
"policy_evaluation": {
"policy_id": "pol_abc123",
"policy_version": 1,
"decision": "auto_approve",
"checks": {
"budget_per_tx": "pass",
"budget_daily": "pass",
"budget_monthly": "pass",
"category": "pass",
"merchant": "pass",
"time_restriction": "pass",
"velocity": "pass"
},
"evaluated_at": "2025-01-15T10:30:00.000Z"
},
"transaction": {
"chain": "solana",
"tx_hash": "5UfDuX...",
"finalized_at": "2025-01-15T10:30:02.000Z"
},
"created_at": "2025-01-15T10:30:00.000Z"
}
Response (Pending Approval)#
{
"payment_id": "pay_770e8400-e29b-41d4-a716-446655440000",
"status": "pending_approval",
"amount": "150.00",
"currency": "USDC",
"merchant_id": "mrc_660e8400-e29b-41d4-a716-446655440000",
"vault_id": "550e8400-e29b-41d4-a716-446655440000",
"agent_id": "agt_550e8400-e29b-41d4-a716-446655440000",
"policy_evaluation": {
"policy_id": "pol_abc123",
"policy_version": 1,
"decision": "request_approval",
"reason": "amount > 100",
"timeout_seconds": 3600,
"fallback": "reject",
"checks": {
"budget_per_tx": "pass",
"budget_daily": "pass",
"budget_monthly": "pass",
"category": "pass",
"merchant": "pass",
"time_restriction": "pass",
"velocity": "pass"
},
"evaluated_at": "2025-01-15T10:30:00.000Z"
},
"approval_url": "https://app.subcent.io/approve/pay_770e8400...",
"created_at": "2025-01-15T10:30:00.000Z"
}
Response (Rejected)#
{
"payment_id": "pay_770e8400-e29b-41d4-a716-446655440000",
"status": "rejected",
"amount": "500.00",
"currency": "USDC",
"merchant_id": "mrc_660e8400-e29b-41d4-a716-446655440000",
"vault_id": "550e8400-e29b-41d4-a716-446655440000",
"agent_id": "agt_550e8400-e29b-41d4-a716-446655440000",
"policy_evaluation": {
"policy_id": "pol_abc123",
"policy_version": 1,
"decision": "reject",
"reason": "Exceeds max_per_transaction limit of 200 USDC",
"checks": {
"budget_per_tx": "fail",
"budget_daily": "pass",
"budget_monthly": "pass"
},
"evaluated_at": "2025-01-15T10:30:00.000Z"
},
"created_at": "2025-01-15T10:30:00.000Z"
}
Errors#
| Error Code | Description |
|---|---|
| agent_not_authorized | The agent does not exist |
| agent_revoked | The agent has been revoked |
| vault_not_found | The agent's vault does not exist |
| vault_frozen | The vault is currently frozen |
| merchant_not_found | The target merchant does not exist |
| merchant_suspended | The merchant is suspended |
| policy_not_found | No active policy exists for this agent |
| policy_violation | The payment violates the spending policy |
| insufficient_balance | The vault does not have enough USDC |
Get Payment#
/v1/payments/:idRetrieve details of a specific payment.
Path Parameters#
| Parameter | Type | Description |
|---|---|---|
| id | string | The payment ID |
Response#
{
"payment_id": "pay_770e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"amount": "25.00",
"currency": "USDC",
"merchant_id": "mrc_660e8400-e29b-41d4-a716-446655440000",
"vault_id": "550e8400-e29b-41d4-a716-446655440000",
"agent_id": "agt_550e8400-e29b-41d4-a716-446655440000",
"policy_evaluation": { ... },
"metadata": { "order_id": "ord_12345" },
"description": "Weekly grocery order",
"category": "groceries",
"transaction": {
"chain": "solana",
"tx_hash": "5UfDuX..."
},
"created_at": "2025-01-15T10:30:00.000Z",
"updated_at": "2025-01-15T10:30:02.000Z"
}
Errors#
| Error Code | Description |
|---|---|
| payment_not_found | No payment exists with the given ID |
List Payments#
/v1/paymentsList payments for a vault with optional filters.
Query Parameters#
| Parameter | Type | Required | Description |
|---|---|---|---|
| vault_id | string | Yes | Filter by vault |
| agent_id | string | No | Filter by agent |
| status | string | No | Filter by status: completed, pending_approval, rejected, failed |
| limit | integer | No | Number of results (default 50, max 200) |
| cursor | string | No | Pagination cursor |
Response#
{
"payments": [
{
"payment_id": "pay_770e8400...",
"status": "completed",
"amount": "25.00",
"currency": "USDC",
"merchant_id": "mrc_660e8400...",
"agent_id": "agt_550e8400...",
"category": "groceries",
"created_at": "2025-01-15T10:30:00.000Z"
}
],
"has_more": false
}
Approve Payment#
/v1/payments/:id/approveApprove a payment that is pending human approval.
When a payment's policy evaluation results in request_approval, it must be approved or rejected by the vault owner. Approving triggers the on-chain transfer.
Path Parameters#
| Parameter | Type | Description |
|---|---|---|
| id | string | The payment ID |
Response#
{
"payment_id": "pay_770e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"transaction": {
"tx_hash": "5UfDuX...",
"finalized_at": "2025-01-15T14:00:05.000Z"
}
}
Errors#
| Error Code | Description |
|---|---|
| payment_not_found | No payment exists with the given ID |
| policy_violation | Payment is not in pending_approval status |
Reject Payment#
/v1/payments/:id/rejectReject a payment that is pending human approval.
Path Parameters#
| Parameter | Type | Description |
|---|---|---|
| id | string | The payment ID |
Request Body (Optional)#
| Field | Type | Required | Description |
|---|---|---|---|
| reason | string | No | Reason for rejection (defaults to "Rejected by user") |
Example Request#
{
"reason": "Amount too high for this vendor"
}
Response#
{
"payment_id": "pay_770e8400-e29b-41d4-a716-446655440000",
"status": "rejected",
"reason": "Amount too high for this vendor"
}
Errors#
| Error Code | Description |
|---|---|
| payment_not_found | No payment exists with the given ID |
| policy_violation | Payment is not in pending_approval status |