REST API Reference
Hosted Base Sepolia API: https://cortex-api.projectaegis.ai
Local development API: http://localhost:3001 (configurable via API_PORT)
Authentication
Reads are public. Mutating routes can require X-Cortex-Api-Key when API_KEY_REQUIRED=true. Stateless compute routes such as /x402/normalize, /x402/verify, and /preflightremain public because they persist nothing.
Health Check
GET /health
{ "status": "ok" }Catalog Documents
Publish Catalog JSON
POST /catalogs
Canonicalizes catalog JSON and stores the canonical bytes by keccak256 hash. Use the returned uri and catalog_hash as the service metadata URI/hash.
{
"catalog_json": "{\n \"merchant\": {...},\n \"services\": [...]\n}",
"expected_hash": "0x...",
"merchant_id": "1",
"service_id": "enrich-company-v1"
}{
"catalog_hash": "0x...",
"merchant_id": "1",
"service_id": "enrich-company-v1",
"size_bytes": 2048,
"uri": "https://cortex-api.projectaegis.ai/catalogs/0x...",
"canonical_json": "{\"merchant\":{},\"services\":[]}"
}Fetch Catalog JSON
GET /catalogs/:hash
Returns canonical JSON text as application/json. Metadata is available at GET /catalogs/:hash/metadata.
Quote Documents
Publish Quote Request
POST /quote-requests
Canonicalizes the agent quote request JSON by keccak256 hash and returns a stable URI.
{
"quote_request_json": "{\n \"request_id\": \"req-001\"\n}",
"expected_hash": "0x...",
"request_id": "req-001",
"merchant_id": "1",
"service_numeric_id": "1",
"service_id": "enrich-company-v1",
"agent": "0x..."
}Publish Quote Response
POST /quote-responses
Canonicalizes the merchant quote response JSON and can link it to a hosted quote request hash.
{
"quote_response_json": "{\n \"request_id\": \"req-001\",\n \"quote\": {...}\n}",
"expected_hash": "0x...",
"request_hash": "0x...",
"request_id": "req-001",
"merchant_id": "1",
"service_numeric_id": "1",
"agent": "0x..."
}Fetch canonical JSON at GET /quote-requests/:hash and GET /quote-responses/:hash. Metadata is available at each route's /metadata path.
Publish License Document
POST /licenses
Canonicalizes a cortex.license.v1 document and returns the hash/URI agents use as license inventory.
{
"license_json": "{\n \"schema\": \"cortex.license.v1\",\n \"issuer\": \"0x...\",\n \"holder\": \"0x...\",\n \"rights\": [\"read\", \"analyze\"]\n}",
"expected_hash": "0x..."
}Check License Use
POST /licenses/check
{
"license_hash": "0x...",
"agent": "0x...",
"action": "commercial_output",
"quote_hash": "0x...",
"receipt_id": "1",
"context": {
"commercial": true,
"model_training": false,
"redistribution": false,
"derivative": true
}
}Inventory is available at GET /licenses with filters for holder, issuer, merchant, service, asset, and active status.
Normalize x402 Payment Requirement
POST /x402/normalize
Normalizes a facilitator payment requirement into the Cortex canonical x402 shape, hashes it, and can compare the result against a quote's x402PayloadHash.
{
"payment_requirement_json": {
"accepts": [{
"scheme": "exact",
"network": "base-sepolia",
"payTo": "0x...",
"asset": "0x...",
"maxAmountRequired": "1000000",
"resource": "https://merchant.example/api/report",
"method": "POST",
"facilitator": { "url": "https://facilitator.example" },
"nonce": "quote-001"
}]
},
"expected_hash": "0x...",
"quote": { "x402_payload_hash": "0x..." }
}{
"normalized": {
"schema": "cortex.x402-payment-requirement.v1",
"scheme": "exact",
"network": "base-sepolia",
"pay_to": "0x...",
"asset": "0x...",
"amount": "1000000"
},
"canonical_json": "{\"amount\":\"1000000\",\"asset\":\"0x...\"}",
"x402_payload_hash": "0x...",
"matches_expected_hash": true,
"matches_quote_hash": true,
"warnings": []
}Agents should sign only after the normalized hash matches the quote-bound hash and policy checks pass.
Publish Encrypted Fulfillment Payload
POST /fulfillment-payloads
Stores canonical encrypted fulfillment payload envelopes by hash. Payloads should contain ciphertext and encryption metadata, not plaintext shipping data.
{
"fulfillment_payload_json": "{\n \"schema\": \"cortex.encrypted-fulfillment.v1\",\n \"ciphertext\": \"base64:...\"\n}",
"expected_hash": "0x...",
"merchant_id": "1",
"agent": "0x...",
"quote_hash": "0x...",
"encryption": "x25519-xsalsa20-poly1305",
"merchant_key_id": "did:key:z6MkMerchantFulfillmentKey"
}Fetch canonical envelope JSON at GET /fulfillment-payloads/:hash. Metadata is available at GET /fulfillment-payloads/:hash/metadata.
Agents
Get Agent by ID
GET /agents/:agentId
{
"agent_id": "1",
"owner": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc",
"metadata_uri": "ipfs://agent-meta",
"pubkey": "0xaabb",
"capabilities_hash": "0x...",
"revoked": false,
"block_number": "10"
}Errors: 400 (invalid ID), 404 (not found)
List Agents by Owner
GET /agents?owner=0x...&limit=50&offset=0
The owner parameter is required.
{
"agents": [...],
"pagination": { "limit": 50, "offset": 0, "count": 1 }
}Intents
Get Intent by ID
GET /intents/:id
{
"intent_id": "1",
"owner": "0x...",
"intent_type": "SWAP_EXACT_IN_MAX_SLIPPAGE",
"input_token": "0x...",
"output_token": "0x...",
"amount_in_max": "1000000000000000000000",
"amount_out_min": "900000000000000000000",
"deadline": "1738965600",
"slippage_bps": "100",
"nonce": "42",
"status": "FILLED",
"block_number": "15",
"fill": {
"solver": "0x...",
"amount_in": "950000000000000000000",
"amount_out": "900000000000000000000",
"tx_hash": "0x...",
"block_number": "18"
}
}If the intent is not filled, fill is null.
List Intents
GET /intents?status=open&limit=50&offset=0
The status filter is optional. Valid values: open, filled, cancelled.
{
"intents": [...],
"pagination": { "limit": 50, "offset": 0, "count": 5 }
}Policies
Get Account Policies
GET /accounts/:address/policies?limit=50&offset=0
{
"account": "0x...",
"policies": [
{
"policy_type": "SPEND_LIMIT",
"token": "0x1111111111111111111111111111111111111111",
"max_per_day": "10000000000000000000000",
"block_number": "12"
},
{
"policy_type": "TARGET_ALLOWLIST",
"target": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512",
"allowed": true,
"block_number": "13"
}
],
"pagination": { "limit": 50, "offset": 0, "count": 2 }
}Commerce
GET /merchants?owner=0x...&active=true — list registered merchants.
GET /merchants/:id — get one merchant.
GET /services?merchant_id=1&capability_hash=0x...&active=true — list services.
GET /services/:id — get one service.
GET /facilitators?active=true — list payment facilitators.
GET /quotes/:quoteHash — get a canonical quote commitment.
GET /receipts?agent=0x...&merchant_id=1 — list settled receipts.
GET /disputes?receipt_id=1 — list receipt-linked disputes.
GET /trust-signals?subject_type=0&subject_id=1 — list trust and risk signals.
GET /merchants/:id/reputation — get receipt, fulfillment, dispute, and trust summaries.
{
"quote_hash": "0x...",
"merchant_id": "1",
"service_numeric_id": "1",
"agent": "0x...",
"token": "0x...",
"facilitator": "0x...",
"amount": "1000000000000000000",
"payment_rail": 3,
"protocol_fee_bps": 0,
"protocol_fee_amount": "0",
"payment_nonce": "1",
"resource_hash": "0x...",
"terms_hash": "0x...",
"x402_payload_hash": "0x...",
"settled": true
}Cortex supports basic wallet transfers, swaps, facilitator-mediated payments, and x402. The x402 payload hash is used only when the selected payment rail is x402.
Commerce Analytics
GET /analytics/commerce
{
"summary": {
"merchants": "1",
"services": "1",
"quotes": "1",
"receipts": "1",
"settled_volume": "1000000000000000000",
"settled_protocol_fees": "0",
"open_disputes": "0"
},
"volume_by_token": [],
"top_merchants": [],
"top_services": [],
"facilitator_volume": [],
"volume_by_payment_rail": [],
"trust_signals_by_kind": []
}Transaction Explain
Explain Transaction
GET /tx/:hash/explain
{
"tx_hash": "0x...",
"block_number": "15",
"summary": "Transaction contained 1 event(s)",
"events": [
{
"eventName": "IntentSubmitted",
"args": { "intentId": "1", "owner": "0x...", "nonce": "42" },
"description": "Intent #1 submitted by 0x..."
}
]
}Common Parameters
| Parameter | Default | Max | Description |
|---|---|---|---|
| limit | 50 | 100 | Results per page |
| offset | 0 | — | Results to skip |
Notes
- All addresses are normalized to lowercase.
- NUMERIC/BIGINT values are returned as strings for BigInt safety.
- All error responses follow the format
{ "error": "message" }.