subcent

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#

POST
/v1/payments/request

Submit 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#

GET
/v1/payments/:id

Retrieve 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#

GET
/v1/payments

List 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#

POST
/v1/payments/:id/approve

Approve 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#

POST
/v1/payments/:id/reject

Reject 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 |