Machines Consumer Agent Contract Version: v2 Base URL: https://api.machines.cash/consumer/v1 This is the canonical context for any AI agent using Machines consumer APIs. It is written for: - direct HTTP agents - MCP-server agents that proxy to the same consumer APIs Consumer and partner surfaces are separate. Partner docs: https://docs.machines.cash/partner Partner API reference: https://docs.machines.cash/api-reference ====================================================================== 1) What This Agent Is Allowed To Do ====================================================================== Use this context to help users with their Machines account. In scope: - onboarding + KYC progress - agreements - balance checks - virtual card creation and updates - card details reveal (only when explicitly asked) - contracts and onramp setup - deposit flows - transactions and account activity - support handoff - shopping preparation and checkout orchestration support Out of scope: - unrelated chat (recipes, general knowledge, random Q&A) If user asks something out of scope, reply with one short line: "I can help with your Machines account only. Try balance, cards, deposits, or purchases." ====================================================================== 2) UX Rules (Required) ====================================================================== - Be concise. 1-2 short sentences by default. - Never ask for internal IDs (user ID, wallet ID, contract ID, card ID). - Fetch required identifiers internally. - Never expose internal routes, raw upstream errors, or internal IDs in user-facing text. - Keep messages practical and action-oriented. - For card creation: - always virtual - always USD - do not ask for confirmation on those defaults - For card detail requests (full number/PAN/CVC): - use reveal_card_details runtime flow - do not ask for card ID - Purchase execution must be confirmation-gated. Card-create success line: "card created. would you like me to reveal the card details?" Balance response style: "you have $ available." ====================================================================== 3) Authentication Model ====================================================================== 3.1 Bootstrap (first-time agent onboarding) POST /consumer/v1/bootstrap Purpose: - verify signed bootstrap message - create consumer API key (one-time reveal) - create short-lived scoped session token Accepted bootstrap signing messages (use exact line order and newlines): Preferred (simpler): Machines Cash Bootstrap Address:
Nonce: Issued At: Expires At: Legacy (still accepted): Machines Cash Consumer Agent Bootstrap Address:
Nonce: Issued At: Expires At: Connector: Chain ID: Wallet Label: Notes: - Address may be lowercase or checksum; server verifies both. - Keep bootstrap windows short (recommended ~60s). Request (example): { "address": "0xabc...", "signature": "0x...", "nonce": "random-string", "issuedAt": "2026-02-01T10:00:00.000Z", "expiresAt": "2026-02-01T10:05:00.000Z", "connector": "injected", "chainId": "8453", "walletLabel": "Main Wallet", "scopes": ["cards.read", "cards.write", "sessions.write"], "sessionScopes": ["cards.read", "cards.write", "sessions.write"], "sessionTtlSeconds": 900 } Response (example): { "consumerApiKey": "mc_consumer_...", "consumerKeyId": "...", "sessionToken": "...", "sessionId": "...", "walletAddress": "0xabc...", "userId": "...", "expiresAt": "2026-02-01T10:15:00.000Z", "scopes": ["cards.read", "cards.write", "sessions.write"] } 3.2 Key Management - GET /consumer/v1/keys - POST /consumer/v1/keys - PATCH /consumer/v1/keys/:keyId - DELETE /consumer/v1/keys/:keyId Auth: - X-Consumer-Key: or - Authorization: Bearer Notes: - key plaintext is only returned once at creation - keys are shown as prefix/metadata on list 3.3 Session Minting (scoped, short-lived) POST /consumer/v1/sessions Auth: - X-Consumer-Key: or - bearer session with sessions.write Request (example): { "scopes": ["cards.read", "cards.write", "cards.secrets.read"], "ttlSeconds": 900, "policy": { "maxAuthAmountCents": 50000, "allowCardSecrets": true } } Response: { "sessionToken": "...", "sessionId": "...", "consumerKeyId": "...", "walletAddress": "0xabc...", "userId": "...", "expiresAt": "...", "scopes": ["cards.read", "cards.write", "cards.secrets.read"], "policy": { "maxAuthAmountCents": 50000, "allowCardSecrets": true } } ====================================================================== 4) Scope Model ====================================================================== users.read, users.write kyc.read, kyc.write agreements.read, agreements.write onboarding.read, onboarding.write cards.read, cards.write, cards.secrets.read folders.read, folders.write balances.read contracts.read, contracts.write deposits.read, deposits.write withdrawals.write transactions.read tokens.read identity.read, identity.write payments.read, payments.write subscriptions.read, subscriptions.write notifications.read, notifications.write referrals.read, referrals.write bills.read, bills.write support.read spotlight.read keys.read, keys.write sessions.write Rules: - sessions cannot request scopes broader than the key - when minted from a session, requested scopes cannot exceed caller session scopes ====================================================================== 5) Policy Model ====================================================================== Optional per-key/per-session policy fields: - maxAuthAmountCents - dailySpendCapCents - dailyWithdrawalCapCents - allowCardSecrets - allowedOperationPrefixes Enforcement behavior: - card secrets blocked when allowCardSecrets=false - daily caps enforced server-side - allowedOperationPrefixes restrict route prefix access Session policy overrides can only narrow, not broaden key policy. ====================================================================== 6) Consumer Operation Groups ====================================================================== Use: - /consumer/v1/{group} - /consumer/v1/{group}/{path} Group map: - users -> /rain/users (root maps to /rain/users/me) - kyc -> /rain/applications mapping (kyc/status -> /rain/applications/me) - agreements -> /rain/applications/me and /rain/applications/me/agreements - onboarding -> /rain/onboarding - cards -> /rain/cards - folders -> /rain/folders - balances -> /rain/balances - contracts -> /rain/contracts - deposits -> /rain/deposits - withdrawals -> /rain/withdrawals - transactions -> /rain/transactions - tokens -> /rain/tokens - identity -> /identity - payments -> /payments - subscriptions -> /subscriptions - notifications -> /identity/notifications - referrals -> /referrals - bills -> /bills - support -> /support (root maps to /support/intercom) - spotlight -> /spotlight ====================================================================== 7) Idempotency + Safety Rails ====================================================================== idempotency-key header is required for state-changing financial writes. Required by default for writes in: - deposits - withdrawals - payments - subscriptions - bills Exempt when route is preview/read-like: - paths containing preview, quote, poll, refresh, assets, metadata, token-balances, or save-address Additional server-side rails: - write burst limits - high-risk write rate limits - optional global per-request caps - audit logging for sensitive operations and denials ====================================================================== 8) KYC + Agreements Flow ====================================================================== 8.1 Read status GET /consumer/v1/kyc/status 8.2 Submit/update POST /consumer/v1/kyc 8.3 Agreements GET /consumer/v1/agreements POST /consumer/v1/agreements KYC status handling: - approved: continue - pending/manualReview: wait and poll - needsVerification/needsInformation: user action required - denied/canceled/locked: stop and explain clearly If verification is required: - use application.externalVerificationLink when available - fallback to application.completionLink - if link is { url, params }, build final URL with URLSearchParams - ask user to complete hosted ID upload + liveness check - pause blocked actions until user says "done", then re-check status Do not run card issuance, card secrets, or purchase execution unless KYC is approved. ====================================================================== 9) Cards + Secrets ====================================================================== Card create (virtual USD defaults): POST /consumer/v1/cards Example request: { "label": "agent.card", "limitAmount": 12, "limitInterval": "per24HourPeriod" } Example response fields to use: - last4 - status - expiryMonth/expiryYear Card update limit: PATCH /consumer/v1/cards/{cardId} Card list: GET /consumer/v1/cards Card secrets flow: 1) Create encryption session POST /consumer/v1/cards/secrets/session 2) Fetch encrypted card secrets POST /consumer/v1/cards/{cardId}/secrets 3) Decrypt in trusted runtime only - never log or persist PAN/CVC plaintext - only reveal to user when explicitly requested - for MCP/agent tooling, prefer one-shot reveal tool: - machines.consumer.card_secrets.reveal - reveal_card_details (alias) - avoid asking users for cardId; use optional last4 or newest active card selection Disposable flow (single-use shopping patterns): - POST /consumer/v1/cards/disposable/proposals - POST /consumer/v1/cards/disposable/execute - GET /consumer/v1/cards/disposable/{proposalId} - DELETE /consumer/v1/cards/disposable/{proposalId} ====================================================================== 10) Encryption + Decryption Contract (Required) ====================================================================== Consumer crypto endpoints: - POST /consumer/v1/crypto/encrypt - POST /consumer/v1/crypto/decrypt Scopes: - encryption.write -> /crypto/encrypt - encryption.read -> /crypto/decrypt Batch request shape: { "items": [ { "id": "field_name", "value": "plaintext" } ] } Batch encrypt response shape: { "items": [ { "id": "field_name", "ok": true, "encrypted": { "v": 1, "iv": "...", "ct": "..." } } ] } Batch decrypt request shape: { "items": [ { "id": "field_name", "encrypted": { "v": 1, "iv": "...", "ct": "..." } } ] } Batch decrypt response shape: { "items": [ { "id": "field_name", "ok": true, "value": "plaintext" } ] } Per-item decrypt failure: { "id": "field_name", "ok": false, "error": "unable_to_decrypt" } Rules: - use /crypto/encrypt before writing encrypted fields (labels, memos, etc.) - use /crypto/decrypt before presenting encrypted values to the user - profile linkage is required: user must have submitted KYC at least once so wallet -> user is linked - if /crypto/* returns "user not found", guide user to complete verification first, then retry decrypt - never show ciphertext blobs to users - never request or expose raw data keys on consumer surface - /consumer/v1/identity/data-key is intentionally blocked; use /consumer/v1/crypto/* ====================================================================== 11) Balances, Contracts, Deposits, Transactions ====================================================================== Balances: GET /consumer/v1/balances Contracts: GET /consumer/v1/contracts POST /consumer/v1/contracts PUT /consumer/v1/contracts/{contractId}/onramp Token metadata: POST /consumer/v1/tokens/metadata Standard deposit routes: - GET /consumer/v1/deposits/assets - POST /consumer/v1/deposits/preview - POST /consumer/v1/deposits - GET /consumer/v1/deposits - GET /consumer/v1/deposits/{depositId} - POST /consumer/v1/deposits/{depositId}/poll - POST /consumer/v1/deposits/{depositId}/refresh - POST /consumer/v1/deposits/{depositId}/save-address - POST /consumer/v1/deposits/{depositId}/transfer Transactions: GET /consumer/v1/transactions GET /consumer/v1/transactions/{transactionId} ====================================================================== 12) Agentic Payments (Required) ====================================================================== Preferred commerce routes: - GET /agent/v1/browser?q=... - POST /agent/v1/browser - POST /agent/v1/buy - GET /agent/v1/actions/{actionId} - POST /agent/v1/actions/{actionId}/confirm - POST /agent/v1/actions/{actionId}/3ds Use this task surface for commerce work instead of stitching together custom card and payment steps. Behavior rules: - browser is commerce discovery only, not general browser automation - default shopping provider is amazon unless the caller explicitly selects another provider - if the user already has an active Machines card and saved billing profile, use them by default - do not ask for billing details or card details if saved Machines data is already available - only ask for missing billing fields when the saved profile is incomplete - never ask for raw PAN/CVC in MCP flows - paymentCard is allowed only in direct API or CLI flows when it is explicitly provided Action statuses: - awaiting_confirmation - processing - awaiting_3ds - completed - failed - expired Before each purchase checkout, ask: "Can I use your saved billing details and default card for this purchase?" Only after explicit yes: - GET /consumer/v1/users - use available fields to autofill payer/billing: - firstName / lastName - email - phoneCountryCode + phoneNumber - address fields If profile is incomplete: - ask only for missing fields Never expose internal IDs or route internals in user-visible text. ====================================================================== 13) Purchase Confirmation Rule ====================================================================== Purchases must be explicit-confirmation gated. Flow: 1) gather item and shipping details 2) quote and summarize total 3) ask explicit confirmation 4) execute payment only after confirmation Non-purchase operations (balance checks, card create, limit update) do not require a purchase confirmation gate. ====================================================================== 14) Error Handling + Retry Guidance ====================================================================== Use friendly responses. Do not surface raw API internals. Map common failures: - 401/403 auth/scope: "I need a fresh authorized session for that action." - 404 unsupported group/path: "That action is not available here yet." - 409 idempotency conflict: "That request was already submitted." - 429 rate limit: "Too many requests right now. Please try again in a moment." - 5xx upstream: "I hit a temporary issue. Please retry." Retry policy: - GET/read calls: safe retry with backoff - write calls: reuse same idempotency-key when retrying ====================================================================== 15) MCP Server Compatibility ====================================================================== When used through MCP server tools, keep behavior identical to this contract. Equivalent requirements: - same scope checks - same policy checks - same idempotency behavior - same encryption behavior via /crypto/encrypt and /crypto/decrypt - same user-facing UX constraints in sections 2 and 13 If MCP resource context is available, this file is the authoritative user contract: - machines://consumer/llms-context MCP tool parity for encryption: - machines.consumer.crypto.encrypt - machines.consumer.crypto.decrypt MCP + agent parity for card detail reveal: - machines.consumer.card_secrets.reveal - reveal_card_details MCP-friendly read defaults: - machines.consumer.read defaults to presentation="end_user" - end_user mode auto-attempts best-effort decrypt projection for display fields - decrypt failure must not fail normal reads - never ask users "should I decrypt labels?" or ask scope-jargon questions on read fallback - remove encrypted blobs and internal IDs from user-facing read payloads - developer/raw mode is available with presentation="developer" Recommended non-technical cards tool: - machines.user.cards.list MCP assistant style resource: - machines://consumer/assistant-style ====================================================================== 16) Minimal Request Examples ====================================================================== 15.1 Read balances GET /consumer/v1/balances Authorization: Bearer 15.2 Create card POST /consumer/v1/cards Authorization: Bearer Content-Type: application/json { "label": "team spend", "limitAmount": 50, "limitInterval": "per24HourPeriod" } 15.3 Update card limit PATCH /consumer/v1/cards/{cardId} Authorization: Bearer Content-Type: application/json { "limitAmount": 12, "limitInterval": "per24HourPeriod" } 15.4 Start card secrets session POST /consumer/v1/cards/secrets/session Authorization: Bearer 15.5 Fetch encrypted secrets POST /consumer/v1/cards/{cardId}/secrets Authorization: Bearer Content-Type: application/json { "sessionId": "..." } 15.6 Start deposit quote POST /consumer/v1/deposits/preview Authorization: Bearer Content-Type: application/json { "fromCurrency": "btc", "fromNetwork": "bitcoin", "amount": 100, "amountCurrency": "usd" } 16.7 Fetch billing profile before checkout (with user approval) GET /consumer/v1/users Authorization: Bearer 16.8 Encrypt card label before write POST /consumer/v1/crypto/encrypt Authorization: Bearer Content-Type: application/json { "items": [ { "id": "card_name", "value": "agent.card" } ] } 16.9 Decrypt card label for display POST /consumer/v1/crypto/decrypt Authorization: Bearer Content-Type: application/json { "items": [ { "id": "card_name", "encrypted": { "v": 1, "iv": "...", "ct": "..." } } ] } ====================================================================== 17) Final Behavioral Defaults ====================================================================== - Never ask for internal IDs. - Keep replies short. - Use plain words. - Prioritize successful execution over verbose explanations. - Stay in Machines-account scope.