openapi: 3.1.0 info: title: Agent Pay — Public Agent, Principal, Intent and Payment API version: 0.4.1-draft summary: Individual and business principals, role-scoped onboarding, Know Your Agent, KYC/KYB, intent verification and one-use card issuance description: | PROPOSED DESIGN — contract under discussion, not a deployed service or network certification. Authentication uses a single BearerAuth scheme across role-aware protected endpoints. Roles: AGENT, PRINCIPAL, ADMIN, PARTNER. Role eligibility is necessary but never sufficient: every resource is checked for ownership, principal binding and partner portfolio scope. 401 is missing/invalid authentication; 403 is a valid actor denied by RBAC/relationship; some unauthorized resource lookups intentionally return 404. A principal is the individual or business on whose behalf an agent acts. Each principal has an immutable principal_type of INDIVIDUAL or BUSINESS and a matching individual or business profile. PRINCIPAL is the role of a trusted principal-scoped session: an individual acts for themselves; a business acts through an authenticated, authorized representative. The service verifies that representative's authority and spending mandate server-side. A business profile, contact email or consent flag is not proof of authority. ADMIN/PARTNER access remains explicitly tenant/portfolio scoped. Identity verification is KYC for individuals and KYB for businesses, including required representative/ownership checks through the trusted provider. It does not grant spending authority. Verification type is determined from principal_type, never chosen by an agent. POST /agents is unauthenticated email-based enrollment. Its opaque one-time enrollment credential is bound to the registration session, valid for a short period, held by the caller and cannot be redeemed until a human verifies email and explicitly approves the agent profile in a trusted hosted flow. /authenticate is a single-call endpoint for initial redemption or ongoing signed-assertion / rotated API-key authentication. Agent identity, principal KYC/KYB, agent binding, purchase intent verification and issuer authorization are distinct trust boundaries. Identity and payment credentials are not permissions to spend. An AI/risk model may inform review/step-up but cannot override hard deterministic restrictions. An agent-provided technology/machine/IP claim is not proven runtime identity; compare signed/stable credentials and server-observed signals. Payment capability creation has a system-controlled nominal 60-second initiation window (not caller configurable). Each virtual-card payment attempt gets a dedicated issuer-processor card identifier stored server-side with credential_id, payment_id and intent_id. Issuer authorization matches on the processor card identifier (or agreed issuer token reference), not name/CVV/expiry. Distinguish authorization retries, reversals and captures to enforce one successful purchase per intent. For network-native agentic rails, equivalent one-purchase transaction binding requires partner validation. POST /intents/{intentId}/pay may return PAN/expiry/CVV one time to an authorized agent in the payment issuance response only, contingent on issuer permissions, PCI-compliant processing and secure delivery. Never persist CVV after authorization, log payment credentials or repeat sensitive card data from GET requests or idempotent replays. A gateway token may be PSP-specific and potentially sensitive; do not treat it as an issuer correlation reference. Cardholder name uses sponsor-approved alphabetic values, never a primary correlation key. Provisioning credentials does not prove a purchase. Normal issuer authorization data includes merchant/amount/MCC/country when available, but not reliably SKU, shipping, billing or PSP checkout URL. Verify these separately from trusted merchant/PSP evidence where possible. All issuer matching/fail-closed behavior, cardholder formats, 3DS timeouts and settlement require bank/PSP validation. contact: name: Agent Pay API design servers: - url: https://api.agentpay.example/v1 description: Placeholder production endpoint, not live - url: https://sandbox.agentpay.example/v1 description: Placeholder sandbox endpoint, not live jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema tags: - name: Agents description: Email-verified enrollment, lifecycle, KYA and principal/agent limits - name: Authentication description: Single-request enrollment redemption or credential-based agent authentication - name: Principals description: Individual/business onboarding, trusted representation and agent binding - {name: Verification, description: Hosted KYC for individuals and KYB for businesses} - name: Intents description: Purchase details and verification against principal authorization - name: Payments description: Payment capability issuance, status and reversal requests - name: Issuer Integration description: Internal issuer/processor-facing, NOT exposed to untrusted agents # No global authentication: requirements differ between public onboarding, # operator accounts, principal sessions, agents, and regulated issuer integrations. security: [] paths: /agents: post: tags: [Agents] operationId: registerAgent summary: Start agent signup with email and declared KYA profile (no bearer token) description: | Public enrollment creates a server-generated agent_id in PENDING_EMAIL_VERIFICATION. A confirmation link is emailed to the address provided. The human must examine and approve the agent purpose and submitted technical profile; email ownership is not proof of agent runtime/framework identity. Response includes an opaque short-lived enrollment credential delivered to the caller only once. It cannot authenticate until email approval is complete, expires, and can be redeemed only once via POST /authenticate. No agent_id, operator_id or bearer token is supplied in this body. Apply bot/rate controls and prevent registration spam and account enumeration. security: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/RegisterAgentRequest'} responses: '201': description: Pending agent signup and email confirmation instructions content: application/json: schema: $ref: '#/components/schemas/AgentEnrollment' example: agent_id: agt_8fd231 enrollment_id: enr_a52e11 status: PENDING_EMAIL_VERIFICATION email_verification_required: true enrollment_credential: enroll_secret_example_one_time expires_at: '2026-10-08T17:30:00Z' message: Verification email sent. Approve the agent profile before authenticating. '400': {$ref: '#/components/responses/BadRequest'} '409': {$ref: '#/components/responses/Conflict'} '429': $ref: '#/components/responses/RateLimited' x-agentpay-roles: - PUBLIC get: tags: [Agents] operationId: listAgents summary: List agents bound to the current principal (role-scoped) description: | PRINCIPAL sees lightweight entries for agents bound to their principal account. AGENT sees its own registered entry unless granted a more specific delegation. ADMIN sees authorized tenant records, PARTNER sees portfolio-scoped entries. Always enforce row-level relationship checks and pagination. security: - BearerAuth: [] parameters: - {$ref: '#/components/parameters/Limit'} - {$ref: '#/components/parameters/Cursor'} - name: status in: query schema: {$ref: '#/components/schemas/AgentStatus'} responses: '200': description: Paginated agents content: application/json: schema: $ref: '#/components/schemas/AgentSummaryList' '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} x-agentpay-roles: - PRINCIPAL - AGENT - ADMIN - PARTNER x-agentpay-resource-authorization: Only bound agents or explicitly authorized tenancy/portfolio agents. /agents/{agentId}: parameters: [$ref: '#/components/parameters/AgentId'] get: tags: [Agents] operationId: getAgent summary: Read agent full profile and observed runtime metadata, access-filtered security: - BearerAuth: [] responses: '200': description: Agent details (public-key metadata only) content: application/json: schema: $ref: '#/components/schemas/AgentDetails' '401': {$ref: '#/components/responses/Unauthorized'} '404': {$ref: '#/components/responses/NotFound'} '403': $ref: '#/components/responses/Forbidden' x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Agent itself, bound principal, or portfolio/tenant authority. Redact sensitive metadata by role. put: tags: [Agents] operationId: updateAgent summary: Update agent configuration description: | Update mutable profile settings. Sensitive verified fields (email, owner, trusted KYA state, runtime signing keys) require independent owner consent and a trusted key-rotation workflow. An AGENT may update its own nonprivileged claims, while owner/ADMIN/PARTNER can change fields allowed by their scope. PUT is treated as a replacement of the mutable agent profile; omission clears optional profile fields, never server-managed identity or trusted observations. security: - BearerAuth: [] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/UpdateAgentRequest'} responses: '200': description: Updated agent content: application/json: schema: {$ref: '#/components/schemas/Agent'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Agent self-service only for declared metadata. Bound owner or privileged actor for owner-controlled fields. /agents/{agentId}/disable: parameters: [$ref: '#/components/parameters/AgentId'] post: tags: [Agents] operationId: disableAgent summary: Disable an agent and prevent further spending description: Blocks new tokens and capabilities; invalidates active agent sessions/capabilities where operationally possible. Does not unwind already authorized purchases. security: - BearerAuth: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] responses: '200': description: Agent disabled content: application/json: schema: {$ref: '#/components/schemas/Agent'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Only verified agent owner or authorized administrator/partner. /agents/{agentId}/enable: parameters: [$ref: '#/components/parameters/AgentId'] post: tags: [Agents] operationId: enableAgent summary: Enable a verified, previously disabled agent description: Re-enablement requires the original operator to remain verified; deleted/revoked agents cannot be re-enabled this way. security: - BearerAuth: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] responses: '200': description: Agent enabled content: application/json: schema: {$ref: '#/components/schemas/Agent'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Only verified agent owner or authorized administrator/partner. /agents/{agentId}/delete: parameters: [$ref: '#/components/parameters/AgentId'] post: tags: [Agents] operationId: deleteAgent summary: Logically delete an agent description: | Soft delete (tombstone), revoke credentials, disable bindings and unused capabilities. Immutable payment and audit records must be retained where required. POST is retained as explicitly requested; this is not physical deletion and cannot be undone by /enable. security: - BearerAuth: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] responses: '200': description: Agent deleted (tombstoned) content: application/json: schema: {$ref: '#/components/schemas/Agent'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Only verified agent owner or authorized administrator/partner. /agents/{agentId}/kya: parameters: [$ref: '#/components/parameters/AgentId'] get: tags: [Agents] operationId: getAgentKya summary: Read the agent Know Your Agent (KYA) assessment description: Separate self-declared information, verified operator/key proofs and server-observed runtime/IP risk signals. Sensitive details may be redacted by role. security: [BearerAuth: []] x-agentpay-roles: [AGENT, PRINCIPAL, ADMIN, PARTNER] x-agentpay-resource-authorization: Self, bound principal or administrative/partner scope. responses: '200': {description: KYA profile and evidence, content: {application/json: {schema: {$ref: '#/components/schemas/AgentKya'}}}} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} /agents/{agentId}/limits: parameters: [$ref: '#/components/parameters/AgentId'] post: tags: [Agents] operationId: createAgentLimits summary: Set initial per-principal agent purchase/weekly/total limits description: > Limits are scoped to the authenticated principal's binding with this agent; a PARTNER or ADMIN must supply the permitted principal_reference where acting on behalf of a principal. Agent self-service cannot create or raise spending authority. All limits cap a separately authenticated principal spending mandate; they do not grant spending authority themselves. Weekly period is a rolling 7 days. security: [BearerAuth: []] x-agentpay-roles: [PRINCIPAL, ADMIN, PARTNER] x-agentpay-resource-authorization: Bound principal or explicitly authorized principal portfolio. parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/SetAgentLimitsRequest'}}}} responses: '201': {description: Limits established, content: {application/json: {schema: {$ref: '#/components/schemas/AgentLimits'}}}} '400': {$ref: '#/components/responses/BadRequest'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} get: tags: [Agents] operationId: getAgentLimits summary: Retrieve current limits and usage for one principal-agent binding description: > PRINCIPAL scope comes from bearer identity. AGENT must supply a bound principal_reference if bound to more than one principal; only authorized data returned. Outstanding reservations count against spend ceilings. security: [BearerAuth: []] x-agentpay-roles: [AGENT, PRINCIPAL, ADMIN, PARTNER] x-agentpay-resource-authorization: Bound principal or approved portfolio; no cross-principal leakage. parameters: - {name: principal_reference, in: query, description: Required for an agent with multiple principal bindings and for privileged delegated reads, schema: {type: string}} responses: '200': {description: 'Limits, spend and reservations', content: {application/json: {schema: {$ref: '#/components/schemas/AgentLimits'}}}} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '401': $ref: '#/components/responses/Unauthorized' put: tags: [Agents] operationId: updateAgentLimits summary: Replace configured purchase/weekly/total limits description: > A change to any limit does not authorize spending by itself. Concurrent reservations and already approved intents remain constrained; enforcement uses the strictest applicable principal/issuer/agent ceiling. All changes audited. security: [BearerAuth: []] x-agentpay-roles: [PRINCIPAL, ADMIN, PARTNER] x-agentpay-resource-authorization: Bound principal or approved portfolio. Agent bearer cannot increase limits. parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/SetAgentLimitsRequest'}}}} responses: '200': {description: Updated limits, content: {application/json: {schema: {$ref: '#/components/schemas/AgentLimits'}}}} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '401': $ref: '#/components/responses/Unauthorized' /authenticate: post: tags: [Authentication] operationId: authenticateAgent summary: Authenticate agent in one call (email enrollment, API key, signed assertion) description: | Initial EMAIL_ENROLLMENT redemption accepts the one-time enrollment credential returned by POST /agents, but only after an owner has verified email and approved the requested profile via the trusted hosted link. Redemption is atomic and issues short-lived access_token, role=AGENT, plus an agent_api_key only once. Never send these credentials by email. Subsequent authentication uses API_KEY (rotatable, revocable and rate limited) or SIGNED_ASSERTION with a registered public key. credential is authentication proof, NEVER a private key. Signed assertions must be fresh, audience-bound and replay protected. A production sender-constrained access token (e.g. DPoP/mTLS) is preferable to a reusable bearer token alone. security: [] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/AuthRequest'} example: agent_id: agt_8fd231 authentication_method: SIGNED_ASSERTION credential: eyJhbGciOiJFUzI1NiIsImtpZCI6ImtleS0xIn0... responses: '200': description: Short-lived agent access token content: application/json: schema: {$ref: '#/components/schemas/AuthResponse'} '400': {$ref: '#/components/responses/BadRequest'} '401': {$ref: '#/components/responses/Unauthorized'} '429': {$ref: '#/components/responses/RateLimited'} x-agentpay-roles: - PUBLIC /principals: post: tags: [Principals] operationId: createPrincipal summary: Onboard an individual or business principal description: | Principal ID is server generated; it is NOT submitted. Idempotency-Key is a retry header, not a bearer credential. An authenticated principal session with explicit onboarding authority or trusted partner/admin channel can create a principal. principal_type selects either an individual or business profile, never both. A business must have a verified authorized representative; contact details do not establish that authority. KYC/KYB verification is a separate process and spending remains blocked where identity verification is required. security: - BearerAuth: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreatePrincipalRequest'} responses: '201': description: Principal profile created content: application/json: schema: {$ref: '#/components/schemas/Principal'} '400': {$ref: '#/components/responses/BadRequest'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} x-agentpay-roles: - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Individual self-onboarding, verified business-representative authority, or explicitly delegated administrative/partner onboarding. /principals/{principalId}: parameters: [$ref: '#/components/parameters/PrincipalId'] get: tags: [Principals] operationId: getPrincipal summary: Retrieve principal profile description: Only the individual, an authorized representative of the subject business, or an explicitly scoped administrative/partner channel may read sensitive profile fields. A contact email does not establish business authority. security: - BearerAuth: [] responses: '200': description: Principal profile content: application/json: schema: {$ref: '#/components/schemas/Principal'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} x-agentpay-roles: - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Self or explicit tenant/portfolio access; no cross-principal read/write. put: tags: [Principals] operationId: updatePrincipal summary: Modify principal details description: Does not accept changes to principal_id, principal_type, verification_status, identity_verification_status, representative authority or externally approved consent. Only the profile matching the stored principal_type can be updated; profile changes may require renewed verification and do not silently update previously verified intents. security: - BearerAuth: [] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/UpdatePrincipalRequest'} responses: '200': description: Updated principal content: application/json: schema: {$ref: '#/components/schemas/Principal'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Self or explicit tenant/portfolio access; no cross-principal read/write. /principals/{principalId}/bind: parameters: [$ref: '#/components/parameters/PrincipalId'] post: tags: [Principals] operationId: bindPrincipalToAgent summary: Bind the authenticated principal to a specified agent description: | Principal-controlled action performed through a trusted channel. Records an explicit consent to establish an association with the agent; it does NOT create carte blanche to spend. The server verifies the authenticated session is scoped to the requested principal and that the agent is eligible. For BUSINESS principals, independently verify the authenticated representative's authority and applicable business spending mandate. An agent cannot approve its own binding or nominate a business representative as proof of consent. A stable, opaque agent-scoped principal_reference is returned. security: - BearerAuth: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/BindPrincipalRequest'} responses: '201': description: Principal-agent binding recorded content: application/json: schema: {$ref: '#/components/schemas/PrincipalBinding'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Principal consent mandatory; admins/partners cannot silently fabricate principal spend approval. /principals/{principalId}/bindings: parameters: [$ref: '#/components/parameters/PrincipalId'] get: tags: [Principals] operationId: listPrincipalBindings summary: List the principal's agent bindings security: - BearerAuth: [] parameters: - {$ref: '#/components/parameters/Limit'} - {$ref: '#/components/parameters/Cursor'} responses: '200': description: Paginated principal bindings content: application/json: schema: {$ref: '#/components/schemas/PrincipalBindingList'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Principal consent mandatory; admins/partners cannot silently fabricate principal spend approval. /principals/{principalId}/bindings/{agentId}: parameters: - {$ref: '#/components/parameters/PrincipalId'} - {$ref: '#/components/parameters/AgentId'} delete: tags: [Principals] operationId: unbindPrincipalFromAgent summary: Revoke an agent binding description: | Disables future intents and unused capabilities under this binding; already-authorized transactions may need separate reversal/refund steps. Audit and transaction records are retained as required. security: - BearerAuth: [] responses: '204': {description: Binding revoked} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Principal consent mandatory; admins/partners cannot silently fabricate principal spend approval. /principals/{principalId}/verification-session: parameters: [$ref: '#/components/parameters/PrincipalId'] post: tags: [Verification] operationId: createPrincipalVerificationSession summary: Create a hosted KYC or KYB verification session for a principal description: > Returns a short-lived hosted verification URL. The authenticated individual or authorized business representative completes verification with a trusted provider, not with the agent. The server selects KYC for INDIVIDUAL or KYB for BUSINESS from the stored principal_type. Business verification includes required representative/ownership checks; a passed KYB result is not a spending mandate. The service accepts verification decisions only from an authenticated provider integration; it must not accept agent-supplied VERIFIED flags. Do not expose PII or submitted identity-document images through these endpoints. security: [BearerAuth: []] x-agentpay-roles: [PRINCIPAL, ADMIN, PARTNER] x-agentpay-resource-authorization: Subject principal or explicitly authorized onboarding partner. parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: required: false content: {application/json: {schema: {$ref: '#/components/schemas/CreatePrincipalVerificationSessionRequest'}}} responses: '201': {description: Hosted principal verification session created, content: {application/json: {schema: {$ref: '#/components/schemas/PrincipalVerificationSession'}}}} '400': {$ref: '#/components/responses/BadRequest'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} /principals/{principalId}/verification: parameters: [$ref: '#/components/parameters/PrincipalId'] get: tags: [Verification] operationId: getPrincipalVerification summary: Read principal KYC/KYB status without disclosing underlying identity documents security: [BearerAuth: []] x-agentpay-roles: [PRINCIPAL, ADMIN, PARTNER] x-agentpay-resource-authorization: Subject principal or authorized onboarding/compliance partner. responses: '200': {description: Current identity verification result, content: {application/json: {schema: {$ref: '#/components/schemas/PrincipalVerification'}}}} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} /intents: post: tags: [Intents] operationId: createIntent summary: Submit comprehensive proposed purchase details description: | An agent submits its understanding of merchant, basket, prices, billing, shipping, checkout channel, PSP and principal authorization reference. Values in this request are agent-declared and must not be treated as verified merchant/issuer evidence. The agent identity is derived from the access token. Principal approval cannot be self-asserted by an agent. The server validates order arithmetic, currency consistency and ownership. Creating an intent neither approves it nor issues a card/token. security: - BearerAuth: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreateIntentRequest'} examples: physicalOrder: summary: A classic browser checkout for a physical product value: principal_reference: pref_agent_abc123 binding_id: bnd_123 purpose: Purchase two books from a named merchant merchant: name: Example Books domain: books.example website_url: https://books.example merchant_reference: books-store-42 country: AT mcc: '5942' cart: items: - sku: BOOK-123 title: Introduction to Computing category: BOOKS kind: PHYSICAL quantity: 2 unit_price: {value: '18.00', currency: EUR} line_total: {value: '36.00', currency: EUR} subtotal: {value: '36.00', currency: EUR} tax_total: {value: '3.60', currency: EUR} shipping_total: {value: '4.90', currency: EUR} discount_total: {value: '0.00', currency: EUR} total: {value: '44.50', currency: EUR} billing: name: Example Principal address: address_line1: Test Street 1 city: Vienna postal_code: '1010' country: AT shipping: recipient_name: Example Principal address: address_line1: Test Street 1 city: Vienna postal_code: '1010' country: AT method: STANDARD checkout: mode: CLASSIC merchant_checkout_url: https://books.example/checkout psp: name: Example PSP payment_page_url: https://checkout.psp.example/session/xyz merchant_order_reference: cart-42 requested_constraints: amount_max: {value: '44.50', currency: EUR} max_authorizations: 1 valid_until: '2026-10-08T15:00:00Z' responses: '201': description: Draft intent created; nothing has been authorized or funded content: application/json: schema: {$ref: '#/components/schemas/Intent'} '400': {$ref: '#/components/responses/BadRequest'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} '409': {$ref: '#/components/responses/Conflict'} '422': {$ref: '#/components/responses/Unprocessable'} x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Agent self and bound principal; ADMIN/PARTNER only within authorized scope. Verify cannot replace principal consent. get: tags: [Intents] operationId: listIntents summary: List intents accessible to the authenticated agent description: Scoped to the agent and its explicitly delegated resources; no cross-principal enumeration. security: - BearerAuth: [] parameters: - {$ref: '#/components/parameters/Limit'} - {$ref: '#/components/parameters/Cursor'} - name: status in: query schema: {$ref: '#/components/schemas/IntentStatus'} - name: principal_reference in: query schema: {type: string} responses: '200': description: Paginated intents content: application/json: schema: {$ref: '#/components/schemas/IntentList'} '401': {$ref: '#/components/responses/Unauthorized'} '403': {$ref: '#/components/responses/Forbidden'} x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Agent self and bound principal; ADMIN/PARTNER only within authorized scope. Verify cannot replace principal consent. /intents/{intentId}: parameters: [$ref: '#/components/parameters/IntentId'] get: tags: [Intents] operationId: getIntent summary: Retrieve intent, verification status and policy reasons security: - BearerAuth: [] responses: '200': description: Intent state and immutable verification evidence references content: application/json: schema: {$ref: '#/components/schemas/Intent'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Agent self and bound principal; ADMIN/PARTNER only within authorized scope. Verify cannot replace principal consent. put: tags: [Intents] operationId: updateIntent summary: Replace an unverified draft intent description: | Only allowed for DRAFT or CHANGES_REQUESTED; replaces the mutable purchase details. Any prior verification result is invalidated. Once verified, the signed purchase snapshot is immutable: create a new intent to change material merchant, amount, product, address or checkout fields. security: - BearerAuth: [] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreateIntentRequest'} responses: '200': description: Updated draft intent content: application/json: schema: {$ref: '#/components/schemas/Intent'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Agent self and bound principal; ADMIN/PARTNER only within authorized scope. Verify cannot replace principal consent. /intents/{intentId}/verify: parameters: [$ref: '#/components/parameters/IntentId'] post: tags: [Intents] operationId: verifyIntent summary: Verify checkout intent against delegation, trusted consent, evidence and policy description: | Separate explicit step from payment credential issuance. Looks up principal-agent binding and actual consent/mandate in a trusted system; a client-supplied consent reference is never independent proof. Performs deterministic hard-rule checks (agent, principal, amount, currency, merchant allowlist, goods/geography, validity, frequency and prior use). Probabilistic risk or AI-based signals may only inform a manual review or step-up decision, not override hard restrictions. If principal approval is missing, returns STEP_UP_REQUIRED with a secure principal action URL. VERIFIED is only set once all required consent and verification succeed. Product, address, and PSP claims can be assessed before checkout using independent evidence where available; they are not assumed observable during standard issuer authorization. Where identity verification is required, an unverified principal cannot receive spend authority; return STEP_UP_REQUIRED with a KYC/KYB verification action, or domain error identity_verification_required as appropriate. Agent KYA and principal/agent limits are independently enforced and untrusted agent profile mismatches inform risk. security: - BearerAuth: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: required: false content: application/json: schema: {$ref: '#/components/schemas/VerifyIntentRequest'} responses: '200': description: Verification decision (including decline or principal step-up) content: application/json: schema: {$ref: '#/components/schemas/IntentVerification'} examples: verified: value: verification_id: vrf_123 intent_id: int_123 decision: APPROVED intent_status: VERIFIED policy_version: '0.3.0' reason_codes: [AGENT_ACTIVE, BINDING_ACTIVE, PRINCIPAL_AUTHORIZED, AMOUNT_WITHIN_LIMIT] verified_snapshot_hash: sha256:0123456789abcdef evidence_id: ev_123 verified_at: '2026-10-08T14:00:00Z' needsStepUp: value: verification_id: vrf_124 intent_id: int_123 decision: STEP_UP_REQUIRED intent_status: STEP_UP_REQUIRED policy_version: '0.3.0' reason_codes: [PRINCIPAL_APPROVAL_REQUIRED] principal_action: authorization_url: https://consent.agentpay.example/approve/opaque expires_at: '2026-10-08T14:05:00Z' evidence_id: ev_124 '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '503': {$ref: '#/components/responses/Unavailable'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Agent self and bound principal; ADMIN/PARTNER only within authorized scope. Verify cannot replace principal consent. /intents/{intentId}/pay: parameters: [$ref: '#/components/parameters/IntentId'] post: tags: [Payments] operationId: requestPaymentCapability summary: Request a one-use payment method for a verified intent description: | Creates one payment attempt for a previously VERIFIED purchase intent. No client TTL parameter. Server sets nominal 60-second one-use capability window. For VIRTUAL_CARD (existing EPHEMERAL_CARD rail) issuer processor issues one unique card identifier per attempt; Agent Pay stores immutable credential_id -> payment_id -> intent_id and issuer processor_card_id mappings. Agent may receive a ONE-TIME sensitive card object (PAN, CVV, expiry, sponsor-approved alphabetic cardholder name) in this POST response if issuance and PCI delivery permit it. All GET endpoints and idempotent replays provide redacted card metadata ONLY. Never log/store CVV after authorization. Network agentic rails can return a separate restricted token handoff; equivalent issuer-token-to-intent binding must be confirmed. Checkout/merchant charges happen outside this API; successful credential issuance does not imply authorization. One intent may have failed/expired payment attempts, but only one distinct successful purchase; issuer auth retries and lifecycle events are deduplicated atomically. security: - BearerAuth: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/RequestPaymentCapability'} example: requested_rail: AUTO responses: '201': description: One-time issued payment payload; sensitive card fields ONLY on first eligible response content: application/json: schema: $ref: '#/components/schemas/PaymentIssuanceResponse' example: payment: payment_id: pay_456 intent_id: int_123 status: CREDENTIAL_ISSUED decision: APPROVED rail: EPHEMERAL_CARD amount: {value: '49.99', currency: EUR} correlation_id: corr_123 capability_id: cap_123 capability_expires_at: '2026-10-08T17:31:00Z' card: {credential_id: cred_789, last4: '1111', gateway_token: {provider: example_psp, token_id: gtw_abc123}} created_at: '2026-10-08T17:30:00Z' updated_at: '2026-10-08T17:30:00Z' card: credential_id: cred_789 pan: '4111111111111111' cvv: '123' expiry_month: '10' expiry_year: '2027' cardholder_name: AGENTPAY RIVER last4: '1111' gateway_token: {provider: example_psp, token_id: gtw_abc123} headers: Cache-Control: description: Sensitive responses must have no-store schema: type: string example: no-store '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '422': description: Includes identity_verification_required when principal KYC/KYB is incomplete content: application/json: schema: $ref: '#/components/schemas/ApiError' example: code: identity_verification_required message: Principal must complete hosted identity verification before spending. correlation_id: corr_123 retryable: false '503': {$ref: '#/components/responses/Unavailable'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Only authorized agent or specifically delegated permitted actor; principal approval and verified intent remain mandatory. get: tags: [Payments] operationId: listIntentPayments summary: List payment IDs, rails, statuses and timestamps (no card secrets) security: - BearerAuth: [] parameters: - {$ref: '#/components/parameters/Limit'} - {$ref: '#/components/parameters/Cursor'} responses: '200': description: Paginated payment attempts content: application/json: schema: $ref: '#/components/schemas/PaymentSummaryList' '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Bound agent, principal or authorized portfolio. Never reveal another principal’s payment details. /intents/{intentId}/pay/{paymentId}: parameters: - {$ref: '#/components/parameters/IntentId'} - {$ref: '#/components/parameters/PaymentId'} get: tags: [Payments] operationId: getIntentPayment summary: Get complete payment record with only token ID and PAN last4 description: | Returns authorized payment metadata, rail, processor-confirmed status, issuer authorization references, safe card details (credential_id, last4 and scope-authorized PSP gateway token ID), but NEVER PAN, CVV or expiration date. The PSP token is not the canonical issuer correlation ID and may still be sensitive. Captured/settled status requires trusted processor events, not agent declaration. security: - BearerAuth: [] responses: '200': description: Payment attempt content: application/json: schema: {$ref: '#/components/schemas/Payment'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Bound agent, principal or authorized portfolio. Never reveal another principal’s payment details. /intents/{intentId}/pay/{paymentId}/reverse: parameters: - {$ref: '#/components/parameters/IntentId'} - {$ref: '#/components/parameters/PaymentId'} post: tags: [Payments] operationId: reverseIntentPayment summary: Request capability cancellation, authorization reversal or merchant refund description: | An unused capability can be cancelled. Reversing an authorization depends on sponsor/issuer/processor support. A captured/settled transaction may require a separate merchant refund, not a card authorization reversal; REFUND_REQUEST is only offered where a permitted integration exists. A success here means a reversal operation was accepted, not that funds were returned. Use the returned status and check actual rail events. API retains /reverse as explicitly requested. security: - BearerAuth: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ReversePaymentRequest'} responses: '202': description: Reversal request received for asynchronous processing content: application/json: schema: {$ref: '#/components/schemas/ReversalOperation'} '400': {$ref: '#/components/responses/BadRequest'} '403': {$ref: '#/components/responses/Forbidden'} '404': {$ref: '#/components/responses/NotFound'} '409': {$ref: '#/components/responses/Conflict'} '422': {$ref: '#/components/responses/Unprocessable'} '401': $ref: '#/components/responses/Unauthorized' x-agentpay-roles: - AGENT - PRINCIPAL - ADMIN - PARTNER x-agentpay-resource-authorization: Bound agent, principal or authorized portfolio. Never reveal another principal’s payment details. /issuer/authorizations/evaluate: post: tags: [Issuer Integration] operationId: evaluateIssuerAuthorization summary: Compare an issuer-reported card authorization with a verified intent description: | Trusted issuer/processor callback. Resolve processor_card_id or agreed credential_reference to one internally issued credential -> payment -> intent. Never use CVV, expiry, cardholder name or gateway token as issuer matching key. Atomically reserve/consume one successful purchase per intent, distinguishing retries/reversals and partial authorizations. Compare actual amount, currency, merchant/MID/MCC/country as available, verified snapshot and system expiry. Shipping, product SKUs, billing address and PSP URL are typically unavailable in an authorization; evidence must be sourced separately, with provenance. No agent API token can call this endpoint. Fail-closed/timeout policy is issuer-agreed. security: - IssuerMutualTLS: [] parameters: [$ref: '#/components/parameters/IdempotencyKey'] requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/IssuerAuthorizationEvent'} responses: '200': description: Deterministic approve/decline recommendation within agreed issuer integration content: application/json: schema: {$ref: '#/components/schemas/IssuerAuthorizationDecision'} '400': {$ref: '#/components/responses/BadRequest'} '401': {$ref: '#/components/responses/Unauthorized'} '409': {$ref: '#/components/responses/Conflict'} '503': {$ref: '#/components/responses/Unavailable'} x-agentpay-roles: - PARTNER x-agentpay-required-permission: issuer.authorizations.evaluate components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT description: > Short-lived actor token (roles AGENT, PRINCIPAL, ADMIN or PARTNER). PRINCIPAL scopes an individual session or an authorized representative acting for a business; onboarding additionally requires explicit onboarding authority. Every operation enforces principal binding/ownership, business representative authority and spending mandate where applicable, or explicitly delegated tenant/partner portfolio scope. IssuerMutualTLS: type: mutualTLS description: Mutually authenticated issuer/processor channel; network and processor trust agreements are additionally required. parameters: IdempotencyKey: in: header name: Idempotency-Key required: true description: Repeat the same logical mutation with the same key and same payload; reuse with a changed payload is a 409. schema: {type: string, minLength: 16, maxLength: 128} AgentId: {name: agentId, in: path, required: true, schema: {type: string, pattern: '^agt_[A-Za-z0-9_-]+$'}} PrincipalId: {name: principalId, in: path, required: true, schema: {type: string, pattern: '^prn_[A-Za-z0-9_-]+$'}} IntentId: {name: intentId, in: path, required: true, schema: {type: string, pattern: '^int_[A-Za-z0-9_-]+$'}} PaymentId: {name: paymentId, in: path, required: true, schema: {type: string, pattern: '^pay_[A-Za-z0-9_-]+$'}} Cursor: {name: cursor, in: query, schema: {type: string}, description: Opaque server-generated pagination cursor} Limit: {name: limit, in: query, schema: {type: integer, minimum: 1, maximum: 100, default: 25}} responses: BadRequest: description: Invalid syntax or input content: {application/json: {schema: {$ref: '#/components/schemas/ApiError'}}} Unauthorized: description: No valid authentication for this actor content: {application/json: {schema: {$ref: '#/components/schemas/ApiError'}}} Forbidden: description: Authenticated actor lacks rights to the resource content: {application/json: {schema: {$ref: '#/components/schemas/ApiError'}}} NotFound: description: Not found or deliberately hidden from this actor content: {application/json: {schema: {$ref: '#/components/schemas/ApiError'}}} Conflict: description: State conflict, optimistic lock or idempotency mismatch content: {application/json: {schema: {$ref: '#/components/schemas/ApiError'}}} Unprocessable: description: Well-formed request fails domain or financial validation content: {application/json: {schema: {$ref: '#/components/schemas/ApiError'}}} RateLimited: description: Too many requests headers: Retry-After: {description: Seconds or HTTP date until retry, schema: {type: string}} content: {application/json: {schema: {$ref: '#/components/schemas/ApiError'}}} Unavailable: description: Dependency unavailable; no implicit authorization or approval content: {application/json: {schema: {$ref: '#/components/schemas/ApiError'}}} schemas: ApiError: type: object additionalProperties: false required: [code, message, correlation_id] properties: code: {type: string, example: INTENT_NOT_VERIFIED} message: {type: string} correlation_id: {type: string} retryable: {type: boolean, default: false} details: type: array items: type: object properties: field: {type: string} reason: {type: string} PageInfo: type: object additionalProperties: false required: [has_more] properties: has_more: {type: boolean} next_cursor: {type: string} AgentStatus: type: string enum: [PENDING_EMAIL_VERIFICATION, PENDING_VERIFICATION, ACTIVE, DISABLED, SUSPENDED, REVOKED, DELETED] PublicJWK: type: object description: Public JSON Web Key; must be structurally validated against allowed algorithms; private JWK attributes are forbidden. required: [kty, kid] properties: kty: {type: string, enum: [EC, RSA, OKP]} kid: {type: string} crv: {type: string} x: {type: string} y: {type: string} n: {type: string} e: {type: string} additionalProperties: false RegisterAgentRequest: type: object additionalProperties: false required: [name, email, purpose, technology, environment] properties: name: {type: string, minLength: 1, maxLength: 120, example: Hermes} email: {type: string, format: email, description: Human operator email that will receive signup confirmation} purpose: {type: string, minLength: 1, maxLength: 2000, example: Personal shopping assistant} description: {type: string, maxLength: 2000} technology: {$ref: '#/components/schemas/AgentTechnology'} environment: {$ref: '#/components/schemas/AgentEnvironment'} capabilities: type: array uniqueItems: true items: {type: string, enum: [SHOPPING, BROWSER_AUTOMATION, API_CHECKOUT, PROCUREMENT, OTHER]} signing_public_key: {$ref: '#/components/schemas/PublicJWK'} metadata: {type: object, additionalProperties: {type: string}} UpdateAgentRequest: type: object additionalProperties: false minProperties: 1 properties: name: {type: string, minLength: 1} purpose: {type: string, minLength: 1} description: {type: string} technology: {$ref: '#/components/schemas/AgentTechnology'} environment: {$ref: '#/components/schemas/AgentEnvironment'} capabilities: {type: array, items: {type: string}} metadata: {type: object, additionalProperties: {type: string}} Agent: type: object additionalProperties: false required: [agent_id, name, purpose, technology, status, created_at, updated_at] properties: agent_id: {type: string, example: agt_8fd231, readOnly: true} name: {type: string} purpose: {type: string} description: {type: string} technology: {$ref: '#/components/schemas/AgentTechnology'} environment: {$ref: '#/components/schemas/AgentEnvironment'} capabilities: {type: array, items: {type: string}} status: {$ref: '#/components/schemas/AgentStatus'} email_verified: {type: boolean} owner_email: {type: string, format: email, description: Redacted for nonowner roles} created_at: {type: string, format: date-time} updated_at: {type: string, format: date-time} AgentList: type: object required: [data, page] properties: data: {type: array, items: {$ref: '#/components/schemas/Agent'}} page: {$ref: '#/components/schemas/PageInfo'} description: Legacy list shape retained only for backward compatibility; GET /agents now returns AgentSummaryList. AuthRequest: type: object additionalProperties: false required: [agent_id, authentication_method, credential] properties: agent_id: {type: string, example: agt_8fd231} authentication_method: {$ref: '#/components/schemas/AuthenticationMethod'} credential: type: string minLength: 1 writeOnly: true description: > EMAIL_ENROLLMENT = single-use registration credential after owner email approval; API_KEY = registered revocable API key; SIGNED_ASSERTION = short-lived JWS/JWT signed using registered private key (never submit the private key itself). AuthResponse: type: object additionalProperties: false required: [access_token, token_type, expires_in, agent_id, role] properties: access_token: {type: string, description: Short-lived bearer access token; never log} token_type: {type: string, const: Bearer} expires_in: {type: integer, minimum: 1, example: 3600} agent_id: {type: string} role: {type: string, const: AGENT} scope: {type: string} agent_api_key: {type: string, description: 'ONLY returned once at successful first EMAIL_ENROLLMENT; store securely, revocable/rotatable; never returned by GET APIs', x-sensitive: true} Address: type: object additionalProperties: false required: [address_line1, city, country] properties: address_line1: {type: string, minLength: 1} address_line2: {type: string} city: {type: string} region: {type: string} postal_code: {type: string} country: {type: string, pattern: '^[A-Z]{2}$', description: ISO 3166-1 alpha-2} PrincipalType: type: string enum: [INDIVIDUAL, BUSINESS] description: The represented individual or business; immutable after onboarding. IndividualPrincipalProfile: type: object additionalProperties: false required: [first_name, last_name] properties: first_name: {type: string, minLength: 1} last_name: {type: string, minLength: 1} BusinessPrincipalProfile: type: object additionalProperties: false required: [legal_name, registration_country] description: Declared business identity, not proof of verification or representative authority. Required evidence is resolved by the trusted KYB provider and policy. properties: legal_name: {type: string, minLength: 1} trading_name: {type: string, minLength: 1} registration_country: {type: string, pattern: '^[A-Z]{2}$'} registration_number: {type: string, minLength: 1} CreatePrincipalRequest: type: object additionalProperties: false required: [principal_type, email] properties: principal_type: {$ref: '#/components/schemas/PrincipalType'} individual: {$ref: '#/components/schemas/IndividualPrincipalProfile'} business: {$ref: '#/components/schemas/BusinessPrincipalProfile'} email: {type: string, format: email} phone: {type: string, description: E.164 preferred} billing_address: {$ref: '#/components/schemas/Address'} shipping_address: {$ref: '#/components/schemas/Address'} locale: {type: string, example: de-AT} oneOf: - properties: {principal_type: {const: INDIVIDUAL}} required: [individual] not: {required: [business]} - properties: {principal_type: {const: BUSINESS}} required: [business] not: {required: [individual]} UpdatePrincipalRequest: type: object additionalProperties: false minProperties: 1 properties: individual: {$ref: '#/components/schemas/IndividualPrincipalProfile'} business: {$ref: '#/components/schemas/BusinessPrincipalProfile'} email: {type: string, format: email} phone: {type: string} billing_address: {$ref: '#/components/schemas/Address'} shipping_address: {$ref: '#/components/schemas/Address'} locale: {type: string} not: {required: [individual, business]} description: Only the nested profile matching the existing principal_type may be supplied. That match is enforced against the stored principal server-side; principal_type and trusted verification/authority fields are immutable through this request. Principal: type: object additionalProperties: false required: [principal_id, principal_type, email, verification_status, created_at, updated_at] properties: principal_id: {type: string, example: prn_123} principal_type: {$ref: '#/components/schemas/PrincipalType'} individual: {$ref: '#/components/schemas/IndividualPrincipalProfile'} business: {$ref: '#/components/schemas/BusinessPrincipalProfile'} email: {type: string, format: email} phone: {type: string} billing_address: {$ref: '#/components/schemas/Address'} shipping_address: {$ref: '#/components/schemas/Address'} locale: {type: string} verification_status: type: string enum: [PENDING, VERIFIED, RESTRICTED] description: Trusted principal onboarding status; never supplied by an agent or self-declared representative. Identity verification and spending authority remain separate checks. created_at: {type: string, format: date-time} updated_at: {type: string, format: date-time} identity_verification_status: $ref: '#/components/schemas/PrincipalVerificationStatus' oneOf: - properties: {principal_type: {const: INDIVIDUAL}} required: [individual] not: {required: [business]} - properties: {principal_type: {const: BUSINESS}} required: [business] not: {required: [individual]} BindPrincipalRequest: type: object additionalProperties: false required: [agent_id, consent_acknowledged] properties: agent_id: {type: string, example: agt_123} consent_acknowledged: type: boolean const: true description: UX acknowledgment; not standalone proof. The trusted principal session and consent record are verified server-side. requested_binding_label: {type: string, description: Friendly label visible to principal} PrincipalBinding: type: object additionalProperties: false required: [binding_id, principal_id, principal_type, agent_id, principal_reference, status, bound_at] properties: binding_id: {type: string, example: bnd_123} principal_id: {type: string} principal_type: {$ref: '#/components/schemas/PrincipalType', readOnly: true} agent_id: {type: string} principal_reference: {type: string, description: 'Opaque, agent-scoped pseudonymous identifier usable in POST /intents'} status: {type: string, enum: [ACTIVE, REVOKED, SUSPENDED]} binding_label: {type: string} consent_evidence_id: {type: string} bound_at: {type: string, format: date-time} revoked_at: {type: string, format: date-time} PrincipalBindingList: type: object required: [data, page] properties: data: {type: array, items: {$ref: '#/components/schemas/PrincipalBinding'}} page: {$ref: '#/components/schemas/PageInfo'} Money: type: object additionalProperties: false required: [value, currency] description: Decimal string to avoid floating point rounding. Enforce ISO 4217 minor-unit precision at runtime (not every currency has two decimal places). properties: value: {type: string, pattern: '^(0|[1-9][0-9]*)(\.[0-9]+)?$', example: '44.50'} currency: {type: string, pattern: '^[A-Z]{3}$', example: EUR} Merchant: type: object additionalProperties: false required: [name, domain] description: Agent-declared merchant attributes; verified MID/acquirer fields may differ at issuer authorization time. properties: name: {type: string} domain: {type: string, example: books.example} website_url: {type: string, format: uri} merchant_reference: {type: string, description: Merchant-provided commerce-system reference} merchant_id: {type: string, description: Acquirer/PSP MID if known; not assumed trustworthy} descriptor: {type: string, description: Anticipated card statement descriptor if known} acquirer_id: {type: string} mcc: {type: string, pattern: '^[0-9]{4}$'} country: {type: string, pattern: '^[A-Z]{2}$'} address: {$ref: '#/components/schemas/Address'} CartItem: type: object additionalProperties: false required: [title, quantity, unit_price, line_total] properties: sku: {type: string} merchant_product_id: {type: string} title: {type: string, minLength: 1} description: {type: string} product_url: {type: string, format: uri} category: {type: string} kind: {type: string, enum: [PHYSICAL, DIGITAL, SERVICE, SUBSCRIPTION, OTHER]} quantity: {type: integer, minimum: 1} unit_price: {$ref: '#/components/schemas/Money'} line_total: {$ref: '#/components/schemas/Money'} tax_amount: {$ref: '#/components/schemas/Money'} attributes: {type: object, additionalProperties: {type: string}} Cart: type: object additionalProperties: false required: [items, subtotal, tax_total, shipping_total, discount_total, total] description: Verify arithmetic across items and totals server-side. Do not accept agent-provided totals at face value. properties: items: type: array minItems: 1 items: {$ref: '#/components/schemas/CartItem'} subtotal: {$ref: '#/components/schemas/Money'} tax_total: {$ref: '#/components/schemas/Money'} shipping_total: {$ref: '#/components/schemas/Money'} discount_total: {$ref: '#/components/schemas/Money'} total: {$ref: '#/components/schemas/Money'} coupon_code: {type: string} BillingDetails: type: object additionalProperties: false required: [name, address] properties: name: {type: string} email: {type: string, format: email} phone: {type: string} address: {$ref: '#/components/schemas/Address'} ShippingDetails: type: object additionalProperties: false required: [recipient_name, address] description: Contains sensitive principal information; may be absent for digital or pickup orders. Not reliably observable from standard card authorization. properties: recipient_name: {type: string} recipient_email: {type: string, format: email} recipient_phone: {type: string} address: {$ref: '#/components/schemas/Address'} method: {type: string, example: STANDARD} carrier: {type: string} pickup_location_reference: {type: string} delivery_instructions: {type: string} PSPDetails: type: object additionalProperties: false properties: name: {type: string, example: Example PSP} merchant_psp_id: {type: string} psp_transaction_reference: {type: string} payment_page_url: {type: string, format: uri, description: 'Agent-observed PSP checkout URL, not available in normal issuer auth'} api_origin: {type: string, format: uri} flow_reference: {type: string} Checkout: type: object additionalProperties: false required: [mode, merchant_checkout_url] properties: mode: type: string enum: [AGENTIC, CLASSIC] description: Agentic-compatible protocol checkout vs ordinary merchant web/PSP checkout. merchant_checkout_url: {type: string, format: uri} cart_url: {type: string, format: uri} merchant_order_reference: {type: string} checkout_session_id: {type: string} psp: {$ref: '#/components/schemas/PSPDetails'} agentic_protocol: {type: string, example: AP2, description: Optional declared protocol label; not proof of compliance} requested_payment_methods: type: array items: {type: string, enum: [CARD, NETWORK_AGENTIC_TOKEN, OTHER]} three_ds_expected: {type: boolean, description: Informational only; actual 3DS is issuer/PSP controlled} callback_url: {type: string, format: uri, description: Pre-authorized webhook/callback target only; must be allowlisted} IntentConstraints: type: object additionalProperties: false required: [amount_max, valid_until, max_authorizations] description: Proposed limits can only narrow a separately trusted principal authorization, never expand it. properties: amount_max: {$ref: '#/components/schemas/Money'} max_authorizations: {type: integer, minimum: 1, default: 1} valid_from: {type: string, format: date-time} valid_until: {type: string, format: date-time} merchant_domains: {type: array, items: {type: string}} merchant_ids: {type: array, items: {type: string}} mcc_allow: {type: array, items: {type: string, pattern: '^[0-9]{4}$'}} country_allow: {type: array, items: {type: string, pattern: '^[A-Z]{2}$'}} item_category_allow: {type: array, items: {type: string}} require_exact_shipping_address_match: {type: boolean, description: Can only be enforced if authenticated checkout evidence exists; not from typical card authorization} require_exact_products_match: {type: boolean, description: Can only be enforced if authenticated checkout evidence exists; not from typical card authorization} AuthorizationReference: type: object additionalProperties: false description: Reference to trusted principal authorization. References supplied by agents must be resolved server-side; self-asserted approvals are not valid. properties: mandate_reference: {type: string, description: 'Existing bank or AP2-style mandate, if supported'} consent_reference: {type: string, description: 'Agent Pay-approved specific principal consent, if available'} principal_approval_context: {type: string, description: Non-authoritative human-readable explanation shown to principal} EvidenceReference: type: object additionalProperties: false required: [type, reference] properties: type: {type: string, enum: [MERCHANT_SIGNED_CART, CHECKOUT_SESSION, CART_HASH, AP2_MANDATE, PSP_SESSION, OTHER]} reference: {type: string, description: Opaque reference or pre-registered evidence URI; content fetched and authenticated by trusted integrations} digest: {type: string, description: Optional sha256 digest; digest alone does not prove source authenticity} issuer: {type: string, description: Claimed issuer of evidence; must be independently verified} CreateIntentRequest: type: object additionalProperties: false required: [principal_reference, binding_id, purpose, merchant, cart, checkout, requested_constraints] properties: principal_reference: {type: string, description: 'Agent-scoped identifier from principal binding, not arbitrary principal account ID'} binding_id: {type: string} purpose: {type: string, minLength: 1, maxLength: 2000} merchant: {$ref: '#/components/schemas/Merchant'} cart: {$ref: '#/components/schemas/Cart'} billing: {$ref: '#/components/schemas/BillingDetails'} shipping: {$ref: '#/components/schemas/ShippingDetails'} checkout: {$ref: '#/components/schemas/Checkout'} requested_constraints: {$ref: '#/components/schemas/IntentConstraints'} authorization_reference: {$ref: '#/components/schemas/AuthorizationReference'} supporting_evidence: type: array items: {$ref: '#/components/schemas/EvidenceReference'} metadata: type: object description: Non-authoritative agent-provided metadata; never used directly as an authorization rule. additionalProperties: {type: string} IntentStatus: type: string enum: [DRAFT, CHANGES_REQUESTED, STEP_UP_REQUIRED, VERIFIED, DECLINED, EXPIRED, CONSUMED, REVOKED] Intent: type: object additionalProperties: false required: [intent_id, agent_id, principal_reference, binding_id, status, purchase, created_at, updated_at] properties: intent_id: {type: string, example: int_123} agent_id: {type: string, description: From authenticated agent token} principal_reference: {type: string} binding_id: {type: string} status: {$ref: '#/components/schemas/IntentStatus'} purchase: {$ref: '#/components/schemas/CreateIntentRequest'} verification: {$ref: '#/components/schemas/IntentVerification'} snapshot_version: {type: integer, minimum: 1} created_at: {type: string, format: date-time} updated_at: {type: string, format: date-time} IntentList: type: object required: [data, page] properties: data: {type: array, items: {$ref: '#/components/schemas/Intent'}} page: {$ref: '#/components/schemas/PageInfo'} VerifyIntentRequest: type: object additionalProperties: false description: Optional request to rerun verification after principal approval or supporting evidence has changed. properties: evidence_references: type: array items: {$ref: '#/components/schemas/EvidenceReference'} note: {type: string, maxLength: 500} PrincipalAction: type: object additionalProperties: false required: [authorization_url, expires_at] properties: authorization_url: {type: string, format: uri, description: 'Hosted HTTPS principal/bank approval page for the individual or authorized business representative; agent may display but cannot approve'} expires_at: {type: string, format: date-time} IntentVerification: type: object additionalProperties: false required: [verification_id, intent_id, decision, intent_status, policy_version, reason_codes, evidence_id] properties: verification_id: {type: string} intent_id: {type: string} decision: {type: string, enum: [APPROVED, STEP_UP_REQUIRED, DECLINED]} intent_status: {$ref: '#/components/schemas/IntentStatus'} policy_version: {type: string} reason_codes: {type: array, items: {type: string}} principal_action: {$ref: '#/components/schemas/PrincipalAction'} verified_snapshot_hash: {type: string, description: Server-generated digest of canonical immutable approved purchase snapshot} checked_evidence: type: array items: {$ref: '#/components/schemas/EvidenceAssessment'} evidence_id: {type: string} verified_at: {type: string, format: date-time} expires_at: {type: string, format: date-time} EvidenceAssessment: type: object additionalProperties: false required: [field_group, assurance] properties: field_group: {type: string, enum: [MERCHANT, CART, BILLING, SHIPPING, CHECKOUT, PRINCIPAL_CONSENT, OTHER]} assurance: {type: string, enum: [DECLARED_ONLY, MATCHED_TO_TRUSTED_SOURCE, CRYPTOGRAPHICALLY_VERIFIED, UNAVAILABLE]} source_reference: {type: string} PaymentRail: type: string enum: [AUTO, VISA_AGENTIC, MASTERCARD_AGENTIC, EPHEMERAL_CARD] RequestPaymentCapability: type: object additionalProperties: false properties: requested_rail: allOf: [$ref: '#/components/schemas/PaymentRail'] default: AUTO description: Optional preference, actual rail determined by Agent Pay policy and availability. description: No TTL field; issuance window is system-controlled. PaymentStatus: type: string enum: [CREATED, STEP_UP_REQUIRED, DECLINED, CREDENTIAL_ISSUED, AUTHORIZATION_PENDING, AUTHORIZED, CAPTURED, SETTLED, EXPIRED, CANCELLED, REVERSED, REFUND_PENDING, REFUNDED, FAILED, OUTCOME_UNKNOWN] CheckoutHandoff: type: object additionalProperties: false required: [type, reference] description: Short-lived opaque credential broker handoff, never reusable PAN/CVV. Secure handoff is limited to authorized execution origin. properties: type: {type: string, enum: [BROKERED_CHECKOUT_TOKEN, NETWORK_AGENTIC_TOKEN_REFERENCE]} reference: {type: string} expires_at: {type: string, format: date-time} Payment: type: object additionalProperties: false required: [payment_id, intent_id, status, decision, amount, correlation_id, created_at, updated_at] properties: payment_id: {type: string, example: pay_123} intent_id: {type: string} correlation_id: {type: string} status: {$ref: '#/components/schemas/PaymentStatus'} decision: {type: string, enum: [APPROVED, STEP_UP_REQUIRED, DECLINED]} amount: {$ref: '#/components/schemas/Money'} rail: type: string enum: [VISA_AGENTIC, MASTERCARD_AGENTIC, EPHEMERAL_CARD] capability_id: {type: string} capability_expires_at: {type: string, format: date-time} checkout_handoff: {$ref: '#/components/schemas/CheckoutHandoff'} issuer_authorization_reference: {type: string, description: Issuer-originated authorization outcome reference} merchant_order_reference: {type: string, description: Merchant-confirmed only if provenance authenticated; otherwise agent-declared} funding_status: {type: string, enum: [NOT_APPLICABLE, PENDING, FUNDED, RESERVED, RELEASED, FAILED], description: 'Optional rail-specific funding, not implied by capability issuance'} reason_codes: {type: array, items: {type: string}} evidence_id: {type: string} created_at: {type: string, format: date-time} updated_at: {type: string, format: date-time} card: $ref: '#/components/schemas/RedactedCard' credential_id: type: string description: Internal public opaque identifier, maps issuer processor card to intent server-side processor_match_status: type: string enum: - NOT_SEEN - MATCHED - MISMATCHED - REVIEW_REQUIRED description: Card metadata is redacted. Only token_id (if scope permits) and PAN last4 may be exposed. No PAN, CVV, expiry or cardholder name on GET. One-use virtual card credentials are emitted only on initial POST /pay. Issuer outcomes must be processor-confirmed. PaymentList: type: object required: [data, page] properties: data: {type: array, items: {$ref: '#/components/schemas/Payment'}} page: {$ref: '#/components/schemas/PageInfo'} description: Legacy detailed list retained for compatibility; GET /pay now returns PaymentSummaryList. ReversePaymentRequest: type: object additionalProperties: false required: [requested_action, reason] properties: requested_action: type: string enum: [CANCEL_UNUSED_CAPABILITY, AUTHORIZATION_REVERSAL, REFUND_REQUEST] description: Explicitly distinguishes cancellation, auth reversal and captured transaction refund. reason: {type: string, enum: [PRINCIPAL_REQUEST, DUPLICATE, MERCHANT_CANCELLED, ERROR, SUSPECTED_FRAUD, OTHER]} reason_detail: {type: string, maxLength: 500} ReversalOperation: type: object additionalProperties: false required: [operation_id, payment_id, requested_action, status, requested_at] properties: operation_id: {type: string} payment_id: {type: string} requested_action: {type: string, enum: [CANCEL_UNUSED_CAPABILITY, AUTHORIZATION_REVERSAL, REFUND_REQUEST]} status: {type: string, enum: [PENDING, COMPLETED, REJECTED, FAILED]} reason_codes: {type: array, items: {type: string}} requested_at: {type: string, format: date-time} completed_at: {type: string, format: date-time} processor_reference: {type: string} IssuerAuthorizationEvent: type: object additionalProperties: false required: - issuer_event_id - amount - merchant - occurred_at description: | The issuer sends its actually available authorization data only; do not invent billing/shipping or product fields. Merchant MID and descriptor matching may need acquirer mappings. Missing mandatory context follows bank-agreed fail-closed rules. properties: issuer_event_id: {type: string, description: Unique issuer/processor event for deduplication} processor_card_id: type: string description: Issuer-processor internal card ID; preferred stable one-attempt-to-one-intent lookup for disposable cards; never a PAN credential_reference: {type: string, description: Fallback opaque issuer network-token or card reference when processor_card_id is not supplied; NOT gateway token ID} amount: {$ref: '#/components/schemas/Money'} merchant: type: object additionalProperties: false required: [descriptor] properties: descriptor: {type: string} merchant_id: {type: string} acquirer_id: {type: string} mcc: {type: string, pattern: '^[0-9]{4}$'} country: {type: string, pattern: '^[A-Z]{2}$'} terminal_id: {type: string} card_auth_reference: {type: string} network_transaction_id: {type: string} network_agentic_indicator: {type: boolean} three_ds: type: object additionalProperties: false description: Issuer-observed 3DS result signals, where available; no assumption of addresses or cart data. properties: eci: {type: string} authentication_status: {type: string} ds_transaction_id: {type: string} optional_enrichment: type: object description: Out-of-band evidence only. The engine must verify the provider, origin and signature before using it as a trusted match signal. additionalProperties: false properties: provenance: {type: string, enum: [MERCHANT_SIGNED, PSP_SIGNED, UNKNOWN]} evidence_reference: {type: string} occurred_at: {type: string, format: date-time} authorization_type: type: string enum: - INITIAL - RETRY - INCREMENTAL - REVERSAL_ADVICE description: Distinguishes a repeat network event from a second purchase; issuer-specific lifecycle mapping required original_authorization_reference: type: string description: Stable prior authorization reference, when applicable anyOf: - required: - processor_card_id - required: - credential_reference IssuerAuthorizationDecision: type: object additionalProperties: false required: [issuer_event_id, decision, reason_codes, correlation_id, evidence_id, policy_version] properties: issuer_event_id: {type: string} decision: type: string enum: [APPROVED, DECLINED] description: Real-time authorization decision; challenge/3DS occurs outside this synchronous issuer contract. reason_codes: {type: array, items: {type: string}} correlation_id: {type: string} intent_id: {type: string} payment_id: {type: string} evidence_id: {type: string} policy_version: {type: string} checked_fields: {type: array, items: {type: string}} unavailable_fields: type: array items: {type: string} example: [product_skus, billing_address, shipping_address, checkout_url] credential_id: type: string description: Issuer-side resolution to Agent Pay credential mapping; not raw card number AgentTechnology: type: object additionalProperties: false required: [platform] properties: platform: {type: string, minLength: 1, example: Hermes, description: 'Registered technology/platform (Hermes, OpenClaw, Dots etc.)'} framework: {type: string, example: Custom Agentic Framework} model: {type: string, example: GPT-6} version: {type: string, example: 1.4.0} provider: {type: string} AgentEnvironment: type: object additionalProperties: false required: [type, country] properties: type: {type: string, enum: [LOCAL, CLOUD, HOSTED, HYBRID, OTHER]} operating_system: {type: string, example: macOS} architecture: {type: string, example: ARM64} country: {type: string, pattern: '^[A-Z]{2}$'} region: {type: string} city: {type: string} hostname: {type: string, description: 'Optional self-declared machine hostname, not proof'} machine_fingerprint: {type: string, description: 'Optional privacy-preserving salted fingerprint, not a device attestation'} AgentEnrollment: type: object additionalProperties: false required: [agent_id, enrollment_id, status, email_verification_required, enrollment_credential, expires_at, message] properties: agent_id: {type: string} enrollment_id: {type: string} status: {type: string, const: PENDING_EMAIL_VERIFICATION} email_verification_required: {type: boolean, const: true} enrollment_credential: {type: string, description: 'Single-use secret retained by the registering runtime, redeemable ONLY after verified email approval; never sent in email', x-sensitive: true} expires_at: {type: string, format: date-time} message: {type: string} AgentObservedRuntime: type: object additionalProperties: false properties: last_seen_ip: {type: string, description: Server-observed ingress IP. Proxies require trusted forwarding configuration.} last_seen_at: {type: string, format: date-time} ip_country: {type: string, pattern: '^[A-Z]{2}$'} observed_environment_mismatch: {type: boolean} last_authentication_method: {type: string} machine_attestation_status: {type: string, enum: [UNAVAILABLE, UNVERIFIED, VERIFIED, REJECTED]} AgentKya: type: object additionalProperties: false required: [agent_id, status, declared, assurance_level] properties: agent_id: {type: string} status: {type: string, enum: [PENDING, VERIFIED, UNDER_REVIEW, RESTRICTED, REVOKED]} assurance_level: {type: string, enum: [SELF_DECLARED, EMAIL_VERIFIED, KEY_BOUND, ATTESTED]} declared: type: object additionalProperties: false properties: name: {type: string} purpose: {type: string} technology: {$ref: '#/components/schemas/AgentTechnology'} environment: {$ref: '#/components/schemas/AgentEnvironment'} verified: type: object additionalProperties: false properties: email_verified: {type: boolean} signing_key_bound: {type: boolean} runtime_attested: {type: boolean} operator_verification_method: {type: string} observed_runtime: {$ref: '#/components/schemas/AgentObservedRuntime'} risk_signals: {type: array, items: {type: string}, description: May affect policy but not a substitute for hard rules} outstanding_actions: {type: array, items: {type: string}} assessed_at: {type: string, format: date-time} AgentSummary: type: object additionalProperties: false required: [agent_id, name, technology, status] properties: agent_id: {type: string} name: {type: string} technology: {type: string, example: OpenClaw, description: Platform label only for list display} status: {$ref: '#/components/schemas/AgentStatus'} AgentSummaryList: type: object additionalProperties: false required: [data, page] properties: data: {type: array, items: {$ref: '#/components/schemas/AgentSummary'}} page: {$ref: '#/components/schemas/PageInfo'} AgentDetails: type: object additionalProperties: false required: [agent_id, name, purpose, technology, status, created_at, updated_at] properties: agent_id: {type: string} name: {type: string} purpose: {type: string} description: {type: string} technology: {$ref: '#/components/schemas/AgentTechnology'} environment: {$ref: '#/components/schemas/AgentEnvironment'} capabilities: {type: array, items: {type: string}} status: {$ref: '#/components/schemas/AgentStatus'} owner_email: {type: string, format: email} kya: {$ref: '#/components/schemas/AgentKya'} observed_runtime: {$ref: '#/components/schemas/AgentObservedRuntime'} created_at: {type: string, format: date-time} updated_at: {type: string, format: date-time} SetAgentLimitsRequest: type: object additionalProperties: false required: [per_purchase, weekly, total] properties: principal_reference: {type: string, description: Only allowed for privileged/agent-scoped delegated context; principal token already determines the principal} per_purchase: {$ref: '#/components/schemas/Money'} weekly: {$ref: '#/components/schemas/Money'} total: {$ref: '#/components/schemas/Money'} weekly_window: {type: string, const: ROLLING_7_DAYS, default: ROLLING_7_DAYS} SpendUsage: type: object additionalProperties: false required: [spent, reserved, available] properties: spent: {$ref: '#/components/schemas/Money'} reserved: {$ref: '#/components/schemas/Money'} available: {$ref: '#/components/schemas/Money'} AgentLimits: type: object additionalProperties: false required: [agent_id, principal_reference, per_purchase, weekly, total, weekly_window, weekly_usage, total_usage, updated_at] properties: agent_id: {type: string} principal_reference: {type: string} per_purchase: {$ref: '#/components/schemas/Money'} weekly: {$ref: '#/components/schemas/Money'} total: {$ref: '#/components/schemas/Money'} weekly_window: {type: string, const: ROLLING_7_DAYS} weekly_usage: {$ref: '#/components/schemas/SpendUsage'} total_usage: {$ref: '#/components/schemas/SpendUsage'} policy_version: {type: string} updated_at: {type: string, format: date-time} AuthenticationMethod: type: string enum: [EMAIL_ENROLLMENT, API_KEY, SIGNED_ASSERTION] description: How the agent proves its identity; never send private keys. PrincipalVerificationStatus: type: string enum: [NOT_STARTED, PENDING, IN_REVIEW, VERIFIED, REJECTED, EXPIRED] PrincipalVerificationType: type: string enum: [KYC, KYB] readOnly: true description: Server-selected KYC for an INDIVIDUAL or KYB for a BUSINESS; verification does not establish spending authority. CreatePrincipalVerificationSessionRequest: type: object additionalProperties: false properties: return_url: {type: string, format: uri, description: 'Optional allowlisted front-end return URL, never an arbitrary redirect target'} locale: {type: string, example: de-AT} PrincipalVerificationSession: type: object additionalProperties: false required: [verification_id, principal_id, verification_type, status, verification_url, expires_at] properties: verification_id: {type: string, example: ver_123456} principal_id: {type: string} verification_type: {$ref: '#/components/schemas/PrincipalVerificationType'} status: {$ref: '#/components/schemas/PrincipalVerificationStatus'} verification_url: {type: string, format: uri, description: 'Hosted provider/Agent Pay verification link for the individual or authorized business representative, never completed by the agent'} expires_at: {type: string, format: date-time} PrincipalVerification: type: object additionalProperties: false required: [principal_id, verification_type, status] properties: principal_id: {type: string} verification_type: {$ref: '#/components/schemas/PrincipalVerificationType'} status: {$ref: '#/components/schemas/PrincipalVerificationStatus'} verification_id: {type: string} verified_at: {type: string, format: date-time} reviewed_at: {type: string, format: date-time} next_action: {type: string, enum: [NONE, START_VERIFICATION, RESUBMIT, WAIT_FOR_REVIEW]} GatewayToken: type: object additionalProperties: false required: [provider, token_id] properties: provider: {type: string, description: Specific PSP or payment gateway whose token this is} token_id: {type: string, description: PSP-specific gateway token; may be reusable/sensitive; only return to authorized actors} usage_scope: {type: string, description: Optional PSP token domain and scope} RedactedCard: type: object additionalProperties: false required: [credential_id, last4] description: Safe payment card reference. No full PAN, CVV, expiry or cardholder name. properties: credential_id: {type: string, description: Agent Pay credential mapping reference} last4: {type: string, pattern: '^[0-9]{4}$'} gateway_token: {$ref: '#/components/schemas/GatewayToken'} OneTimeVirtualCard: type: object additionalProperties: false required: [credential_id, pan, cvv, expiry_month, expiry_year, cardholder_name, last4] description: > HIGHLY SENSITIVE: returned at most once on authorized initial POST /pay over controlled PCI-compliant delivery. Never exposed by GET, logs, analytics or replay. CVV must not be stored post authorization. This schema increases PCI scope. properties: credential_id: {type: string} pan: {type: string, pattern: '^[0-9]{12,19}$', description: Card number for one-use checkout; sample data only in docs, x-sensitive: true} cvv: {type: string, pattern: '^[0-9]{3,4}$', description: Transient card security value; never log or store after authorization, x-sensitive: true} expiry_month: {type: string, pattern: '^(0[1-9]|1[0-2])$'} expiry_year: {type: string, pattern: '^[0-9]{4}$'} cardholder_name: {type: string, pattern: '^[A-Z ]+$', example: AGENTPAY RIVER, description: Sponsor-approved alphabetic dictionary value; not used for transaction binding} last4: {type: string, pattern: '^[0-9]{4}$'} gateway_token: {$ref: '#/components/schemas/GatewayToken'} PaymentIssuanceResponse: type: object additionalProperties: false required: [payment] description: > Payment record and optional ONE-TIME card payload for virtual-card rail. When creating a network-native agentic token, network_capability may be returned instead of card. No full credentials on repeat requests or GET responses. properties: payment: {$ref: '#/components/schemas/Payment'} card: {$ref: '#/components/schemas/OneTimeVirtualCard'} network_capability: {$ref: '#/components/schemas/CheckoutHandoff'} PaymentSummary: type: object additionalProperties: false required: [payment_id, intent_id, rail, status, created_at] properties: payment_id: {type: string} intent_id: {type: string} rail: {type: string, enum: [VISA_AGENTIC, MASTERCARD_AGENTIC, EPHEMERAL_CARD]} status: {$ref: '#/components/schemas/PaymentStatus'} created_at: {type: string, format: date-time} updated_at: {type: string, format: date-time} PaymentSummaryList: type: object additionalProperties: false required: [data, page] properties: data: {type: array, items: {$ref: '#/components/schemas/PaymentSummary'}} page: {$ref: '#/components/schemas/PageInfo'}