{"openapi":"3.1.0","info":{"version":"0.1.0","title":"Soren Pay API","description":"Programmable Visa infrastructure for AI agents and Web3 cross-border treasuries."},"servers":[{"url":"https://api.sorenpay.dev"}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"apk_*"}},"schemas":{},"parameters":{}},"paths":{"/api/workspaces":{"post":{"summary":"Create a workspace","description":"Provisions a Column FBO sub-account + Reap merchant + first apk_ API key. Returns the secret once.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":80},"plan":{"type":"string","enum":["alpha","growth"],"default":"alpha"}},"required":["name"]}}}},"responses":{"200":{"description":"Workspace created"}}},"get":{"summary":"List workspaces","responses":{"200":{"description":"OK"}}}},"/api/auth/keys":{"post":{"summary":"Provision an API key","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bearer apk_…"},"required":true,"name":"authorization","in":"header"},{"schema":{"type":"string","format":"uuid","description":"24h replay-safe key, recommended on all POSTs."},"required":false,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":40},"scopes":{"type":"array","items":{"type":"string"},"default":[]}},"required":["label"]}}}},"responses":{"200":{"description":"Key + one-time secret"}}},"get":{"summary":"List API keys","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"OK"}}},"delete":{"summary":"Revoke an API key","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"query"}],"responses":{"200":{"description":"Revoked"}}}},"/api/cards":{"post":{"summary":"Mint a virtual card","description":"Scopes (MCC + merchant allowlist) and limits (per-txn + monthly) are enforced by the authorization engine in <200ms per swipe.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bearer apk_…"},"required":true,"name":"authorization","in":"header"},{"schema":{"type":"string","format":"uuid","description":"24h replay-safe key, recommended on all POSTs."},"required":false,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"holderKind":{"type":"string","enum":["agent","human"]},"holderLabel":{"type":"string","minLength":1,"maxLength":60},"cardholderId":{"type":"string"},"monthlyLimitUsdCents":{"type":"integer","exclusiveMinimum":0},"perTxnLimitUsdCents":{"type":"integer","exclusiveMinimum":0},"allowedMccs":{"type":["array","null"],"items":{"type":"string","pattern":"^\\d{4}$"}},"allowedMerchants":{"type":["array","null"],"items":{"type":"string","minLength":1,"maxLength":80}}},"required":["holderKind","holderLabel","monthlyLimitUsdCents","perTxnLimitUsdCents"]}}}},"responses":{"200":{"description":"Card minted"}}},"get":{"summary":"List cards","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"OK"}}}},"/api/cards/{id}":{"patch":{"summary":"Update card (state, limits, scopes)","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["active","frozen","terminated"]},"monthlyLimitUsdCents":{"type":"integer","exclusiveMinimum":0},"perTxnLimitUsdCents":{"type":"integer","exclusiveMinimum":0},"allowedMccs":{"type":["array","null"],"items":{"type":"string","pattern":"^\\d{4}$"}},"allowedMerchants":{"type":["array","null"],"items":{"type":"string","minLength":1,"maxLength":80}}}}}}},"responses":{"200":{"description":"Updated"}}}},"/api/treasury":{"get":{"summary":"Treasury snapshot + 25 recent ledger entries","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"OK"}}}},"/api/treasury/deposits":{"post":{"summary":"Sandbox: ingest a deposit","description":"Sandbox-only. In production deposits arrive via the column-transfer or reap-stablecoin-deposit webhooks.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bearer apk_…"},"required":true,"name":"authorization","in":"header"},{"schema":{"type":"string","format":"uuid","description":"24h replay-safe key, recommended on all POSTs."},"required":false,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"source":{"type":"string","enum":["column_fiat"]},"rail":{"type":"string","enum":["ach","fednow","wire"]},"amountUsdCents":{"type":"integer","exclusiveMinimum":0}},"required":["source","rail","amountUsdCents"]},{"type":"object","properties":{"source":{"type":"string","enum":["reap_stablecoin"]},"asset":{"type":"string","enum":["USDC","USDT"]},"chain":{"type":"string","enum":["ethereum","polygon","arbitrum","solana"]},"amountUsdCents":{"type":"integer","exclusiveMinimum":0}},"required":["source","asset","chain","amountUsdCents"]}]}}}},"responses":{"200":{"description":"Ledger credit + provider receipt"}}}},"/api/physical-cards":{"post":{"summary":"Order a physical metal card","description":"Unlocks on either a $99 premium fee OR a $5,000 balance commit. Triggers Reap manufacturing queue.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bearer apk_…"},"required":true,"name":"authorization","in":"header"},{"schema":{"type":"string","format":"uuid","description":"24h replay-safe key, recommended on all POSTs."},"required":false,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"holderLabel":{"type":"string","minLength":1,"maxLength":60},"finish":{"type":"string","enum":["standard","metal"],"default":"metal"},"unlockMethod":{"type":"string","enum":["premium_99","balance_commit_5000"]},"monthlyLimitUsdCents":{"type":"integer","exclusiveMinimum":0},"perTxnLimitUsdCents":{"type":"integer","exclusiveMinimum":0},"shipping":{"type":"object","properties":{"line1":{"type":"string","minLength":2,"maxLength":120},"line2":{"type":"string","maxLength":120},"city":{"type":"string","minLength":1,"maxLength":80},"region":{"type":"string","minLength":1,"maxLength":80},"postalCode":{"type":"string","minLength":2,"maxLength":20},"country":{"type":"string","minLength":2,"maxLength":2}},"required":["line1","city","region","postalCode","country"]}},"required":["holderLabel","unlockMethod","monthlyLimitUsdCents","perTxnLimitUsdCents","shipping"]}}}},"responses":{"200":{"description":"Card + order + ETA"}}}},"/api/agents":{"post":{"summary":"Register an AI agent","description":"Generates an Ed25519 keypair, persists the public key + fingerprint, binds to Reap × Visa, and returns the private key once. Store the private key in your agent runtime's secret store.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bearer apk_…"},"required":true,"name":"authorization","in":"header"},{"schema":{"type":"string","format":"uuid","description":"24h replay-safe key, recommended on all POSTs."},"required":false,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"agentName":{"type":"string","minLength":1,"maxLength":80},"description":{"type":"string","maxLength":200},"protocols":{"type":"array","items":{"type":"string","enum":["TAP","MPP","ACP"]},"default":["TAP","MPP","ACP"]},"publicKeyPem":{"type":"string","minLength":50}},"required":["agentName"]}}}},"responses":{"200":{"description":"Agent + one-time private key"}}},"get":{"summary":"List workspace agents","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"OK"}}}},"/api/agents/{id}":{"patch":{"summary":"Update agent state (active / frozen / terminated)","description":"Terminated is irreversible. Mirrors the state to Reap in live mode.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["active","frozen","terminated"]}},"required":["state"]}}}},"responses":{"200":{"description":"Updated agent"}}}},"/api/agents/{id}/intents":{"post":{"summary":"Submit a signed payment intent","description":"Verifies Ed25519 signature, intent freshness (iat/exp), and replay protection (unique intent_id). Persists to agent_intent_log either way for audit trail. Returns 422 on replay, 401 on bad signature.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"intent":{"type":"object","properties":{"agent_id":{"type":"string"},"merchant":{"type":"object","properties":{"name":{"type":"string"},"mcc":{"type":"string","pattern":"^\\d{4}$"},"reap_merchant_id":{"type":"string"}},"required":["name","mcc"]},"amount":{"type":"object","properties":{"currency":{"type":"string","minLength":3,"maxLength":3},"cents":{"type":"integer","exclusiveMinimum":0}},"required":["currency","cents"]},"funding":{"type":"object","properties":{"asset":{"type":"string","enum":["USDC","USDT","BTC","ETH","SOL"]},"chain":{"type":"string","enum":["ethereum","polygon","arbitrum","base","optimism","solana"]}}},"intent_id":{"type":"string","minLength":1,"maxLength":120},"iat":{"type":"integer"},"exp":{"type":"integer"},"protocol":{"type":"string","enum":["TAP","MPP","ACP"]},"description":{"type":"string","maxLength":200}},"required":["agent_id","merchant","amount","intent_id","iat","exp","protocol"]},"signature":{"type":"string","minLength":1},"key_id":{"type":"string","minLength":1}},"required":["intent","signature","key_id"]}}}},"responses":{"200":{"description":"Intent accepted + logged"},"401":{"description":"Signature invalid or expired"},"422":{"description":"Replay (duplicate intent_id)"}}},"get":{"summary":"Audit log of submitted intents","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Last 50 intents (incl. invalid)"}}}},"/api/ramp/onramp/sessions":{"post":{"summary":"Create a Reap-hosted onramp session","description":"Returns a hosted URL the user is redirected to. Reap handles KYC + bank-connect + USDC settlement, then fires /api/webhooks/reap-onramp on completion.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bearer apk_…"},"required":true,"name":"authorization","in":"header"},{"schema":{"type":"string","format":"uuid","description":"24h replay-safe key, recommended on all POSTs."},"required":false,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"amountUsdCents":{"type":"integer","exclusiveMinimum":0},"sourceCurrency":{"type":"string","enum":["USD","EUR","HKD","GBP","SGD","JPY"]},"destinationAsset":{"type":"string","enum":["USDC","USDT"]},"destinationChain":{"type":"string","enum":["ethereum","polygon","arbitrum","base","optimism","solana"]},"redirectUrl":{"type":"string","format":"uri"}},"required":["amountUsdCents","sourceCurrency","destinationAsset","destinationChain","redirectUrl"]}}}},"responses":{"200":{"description":"Onramp session + hosted URL"}}},"get":{"summary":"List workspace onramp sessions","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"OK"}}}},"/api/ramp/offramp/sessions":{"post":{"summary":"Withdraw stablecoin to bank","description":"USDC/USDT → fiat via SWIFT / SEPA / FPS / ACH / wire / local rails. Posts hold to ledger on creation; reversed on `failed` webhook.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bearer apk_…"},"required":true,"name":"authorization","in":"header"},{"schema":{"type":"string","format":"uuid","description":"24h replay-safe key, recommended on all POSTs."},"required":false,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sourceAsset":{"type":"string","enum":["USDC","USDT"]},"sourceChain":{"type":"string","enum":["ethereum","polygon","arbitrum","base","optimism","solana"]},"amountUsdCents":{"type":"integer","exclusiveMinimum":0},"destinationCurrency":{"type":"string","enum":["USD","EUR","HKD","GBP","SGD","JPY"]},"beneficiary":{"type":"object","properties":{"type":{"type":"string","enum":["bank_account"]},"accountHolderName":{"type":"string","minLength":2,"maxLength":160},"accountNumber":{"type":"string"},"routingNumber":{"type":"string"},"iban":{"type":"string"},"swiftBic":{"type":"string"},"countryCode":{"type":"string","minLength":2,"maxLength":2}},"required":["type","accountHolderName","countryCode"]},"preferredRail":{"type":"string","enum":["SWIFT","SEPA","FPS","ACH","WIRE","LOCAL"]}},"required":["sourceAsset","sourceChain","amountUsdCents","destinationCurrency","beneficiary"]}}}},"responses":{"200":{"description":"Offramp session + ETA"}}}},"/api/ramp/sessions/{id}":{"get":{"summary":"Get a ramp session by id","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Session"}}}},"/api/ramp/quote":{"post":{"summary":"Pre-flight off-ramp quote (stablecoin → fiat)","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sourceAsset":{"type":"string","enum":["USDC","USDT"]},"amountUsdCents":{"type":"integer","exclusiveMinimum":0},"destinationCurrency":{"type":"string","enum":["USD","EUR","HKD","GBP","SGD","JPY"]}},"required":["sourceAsset","amountUsdCents","destinationCurrency"]}}}},"responses":{"200":{"description":"destination_amount, fee, rate, ETA"}}}},"/api/payments/international/quote":{"post":{"summary":"Quote a cross-border payment","description":"Reap Payment API quote: rate, fee, rail, ETA. Stablecoin → 10+ destination currencies via SWIFT/SEPA/FPS/local.","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sourceAsset":{"type":"string","enum":["USDC","USDT"]},"amountUsdCents":{"type":"integer","exclusiveMinimum":0},"destinationCurrency":{"type":"string","minLength":3,"maxLength":3},"destinationCountry":{"type":"string","minLength":2,"maxLength":2}},"required":["sourceAsset","amountUsdCents","destinationCurrency","destinationCountry"]}}}},"responses":{"200":{"description":"Quote"}}}},"/api/payments/international":{"post":{"summary":"Originate a cross-border payment","description":"USDC/USDT bridge → fiat to beneficiary. T+0 settlement within UTC+8 banking window. Posts source-side hold on the ledger; reversed on `failed`.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bearer apk_…"},"required":true,"name":"authorization","in":"header"},{"schema":{"type":"string","format":"uuid","description":"24h replay-safe key, recommended on all POSTs."},"required":false,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sourceAsset":{"type":"string","enum":["USDC","USDT"]},"sourceChain":{"type":"string","enum":["ethereum","polygon","arbitrum","base","optimism","solana"]},"amountUsdCents":{"type":"integer","exclusiveMinimum":0},"destinationCurrency":{"type":"string","minLength":3,"maxLength":3},"destinationCountry":{"type":"string","minLength":2,"maxLength":2},"beneficiary":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":160},"email":{"type":"string","format":"email"},"accountNumber":{"type":"string"},"iban":{"type":"string"},"swiftBic":{"type":"string"},"routingNumber":{"type":"string"},"countryCode":{"type":"string","minLength":2,"maxLength":2},"localAccountId":{"type":"string"}},"required":["name","countryCode"]},"quoteId":{"type":"string"},"description":{"type":"string","maxLength":200}},"required":["sourceAsset","sourceChain","amountUsdCents","destinationCurrency","destinationCountry","beneficiary"]}}}},"responses":{"200":{"description":"Payment + ETA"}}},"get":{"summary":"List workspace international payments","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"OK"}}}},"/api/payments/international/{id}":{"get":{"summary":"Get an international payment by id","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Payment"}}}},"/api/v1/checkout/sessions":{"post":{"summary":"Create a hosted checkout session","description":"Returns a session id + hostedUrl. Customer pays at the hosted URL with any wallet; the on-chain confirmation worker drives the FSM to `completed` and posts a stablecoin ledger credit to the merchant workspace.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bearer apk_…"},"required":true,"name":"authorization","in":"header"},{"schema":{"type":"string","format":"uuid","description":"24h replay-safe key, recommended on all POSTs."},"required":false,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"amountUsdCents":{"type":"integer","exclusiveMinimum":0},"merchantReference":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":500},"acceptedAssets":{"type":"array","items":{"type":"string","enum":["USDC","USDT","ETH","BTC","SOL"]},"minItems":1,"default":["USDC"]},"acceptedChains":{"type":"array","items":{"type":"string","enum":["ethereum","polygon","arbitrum","base","optimism","solana","bitcoin"]},"minItems":1,"default":["ethereum","polygon","arbitrum","base","solana"]},"successUrl":{"type":"string","format":"uri"},"cancelUrl":{"type":"string","format":"uri"},"expiresInSeconds":{"type":"integer","minimum":300,"maximum":86400,"default":1800},"settlementOption":{"type":"string","enum":["hold_stablecoin","convert_to_fiat"],"default":"hold_stablecoin"},"metadata":{"type":"object","additionalProperties":{}}},"required":["amountUsdCents","successUrl"]}}}},"responses":{"200":{"description":"Session + hostedUrl"}}},"get":{"summary":"List workspace checkout sessions","security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Last 50 sessions"}}}},"/api/v1/checkout/sessions/{id}":{"get":{"summary":"Get a checkout session (merchant-side, full row)","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Session"},"404":{"description":"Not found"}}}},"/api/v1/checkout/sessions/{id}/status":{"get":{"summary":"Public — customer-safe status poll","description":"No auth — used by the hosted page. Returns status, confirmations, selected (asset, chain, address). Auto-expires the session if past TTL.","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Status snapshot"}}}},"/api/v1/checkout/sessions/{id}/select":{"post":{"summary":"Public — customer picks (asset, chain)","description":"No auth. Pins the receiving address and enqueues the on-chain confirmation watcher.","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"asset":{"type":"string","enum":["USDC","USDT","ETH","BTC","SOL"]},"chain":{"type":"string","enum":["ethereum","polygon","arbitrum","base","optimism","solana","bitcoin"]}},"required":["asset","chain"]}}}},"responses":{"200":{"description":"Pinned address"}}}},"/api/wallets/refresh":{"post":{"summary":"On-demand refresh of a linked wallet's multi-chain balance","description":"Enqueues a `balance-refresh` BullMQ job to query Alchemy/Helius/Blockstream and upsert into `funding_balances`. Returns 202 with the job id. The recurring 5-min tick covers the steady state.","security":[{"BearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Bearer apk_…"},"required":true,"name":"authorization","in":"header"},{"schema":{"type":"string","format":"uuid","description":"24h replay-safe key, recommended on all POSTs."},"required":false,"name":"idempotency-key","in":"header"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"accountKind":{"type":"string","enum":["workspace","personal"]},"accountId":{"type":"string"},"address":{"type":"string"},"chains":{"type":"array","items":{"type":"string"},"minItems":1}},"required":["accountKind","accountId","address","chains"]}}}},"responses":{"202":{"description":"Enqueued"}}}},"/api/mcp":{"post":{"summary":"Model Context Protocol JSON-RPC endpoint","description":"JSON-RPC 2.0 server speaking MCP 2024-11-05. Methods: `initialize`, `tools/list`, `tools/call`, `ping`. Authenticated via the same `Authorization: Bearer apk_…` header as the REST API; each tool checks the apk_ key's required scope. Used by Claude Desktop (via the `@sorenpay/mcp-bridge` npm package), Cursor, Windsurf, and any custom MCP client. See `/dashboard/developers/mcp` for the merchant-facing quickstart.","security":[{"BearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"null"},{"type":"null"}]},"method":{"type":"string"},"params":{}},"required":["jsonrpc","method"]}}}},"responses":{"200":{"description":"JSON-RPC response (success or error envelope)"}}}}},"webhooks":{}}