Allowance Mandates API

The Mandates API from Allowance — 5 operation(s) for mandates.

OpenAPI Specification

allowance-mandates-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: Allowance Mandates API
  version: 0.1.0-pre-launch
  description: 'Consumer trust layer for AI agent payments.


    ## How it works


    1. **Agent proposes a mandate.** The agent calls `POST /v1/mandates` with a suggested amount, merchant, and cadence. The mandate starts in `pending_approval` status.

    2. **Human approves the mandate.** The mandate owner receives a notification (push, email, or in-app) and approves it. The mandate becomes `active`. The agent never triggers this step — it waits.

    3. **Agent requests a virtual card.** When a purchase is needed, the agent calls `POST /v1/mandates/{id}/credential-requests`. Allowance automatically validates the request against the mandate rules (amount, merchant, time period). No human involvement. If valid, a single-use virtual card (PAN, expiry, CVV) is returned — the agent uses it like a card number at checkout. If not, the request is denied with reasons.

    4. **Mandate lifecycle.** For `cadence: "once"` (immediate) mandates, the mandate auto-expires after the first virtual card is issued. For recurring mandates, the mandate stays active and the agent can request a new virtual card on each purchase cycle within the defined rules.


    ## AP2 compatibility


    This API is designed to be a natural precursor to the [AP2 Agent Payments Protocol](https://ap2-protocol.org). The Allowance mandate maps directly to AP2''s Intent Mandate (human-not-present scenario). In a future AP2-compatible version, the mandate will be a cryptographically signed Verifiable Digital Credential (VDC), and human approval will produce a non-repudiable cryptographic attestation rather than an in-system state change. The same concepts and fields carry forward.


    **Status: Pre-launch.** All endpoints return `501 Not Implemented`. Contact hello@useallowance.com for early access.'
  contact:
    name: Allowance
    email: hello@useallowance.com
    url: https://useallowance.com/
  x-pre-launch: true
  x-status-url: https://useallowance.com/status.json
  x-ap2-compatible: true
servers:
- url: https://api.useallowance.com/v1
  description: Production (pre-launch — not yet active)
security:
- ApiKeyAuth: []
tags:
- name: Mandates
paths:
  /mandates:
    post:
      operationId: createMandate
      summary: Propose a spending mandate
      description: 'The agent proposes a mandate with a suggested budget, merchant restrictions, and cadence. The mandate is created with `status: pending_approval` and is not usable until the human owner approves it out-of-band (via push notification, email, or in-app review). The agent should poll `GET /v1/mandates/{id}` to detect when status becomes `active`.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateMandateRequest'
            examples:
              flight:
                $ref: '#/components/examples/FlightMandate'
              household:
                $ref: '#/components/examples/HouseholdMandate'
              subscriptions:
                $ref: '#/components/examples/SubscriptionMandate'
      parameters:
      - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '201':
          description: Mandate created in `pending_approval` status
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AllowanceMandate'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '501':
          $ref: '#/components/responses/NotImplemented'
      tags:
      - Mandates
  /mandates/{id}:
    get:
      operationId: getMandate
      summary: Retrieve a mandate
      description: 'Poll this endpoint to check whether the human has approved the mandate (`status: active`). Also use it to check remaining budget and expiry before requesting a credential.'
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          pattern: ^mnd_
        description: 'Mandate ID (prefix: mnd_)'
      responses:
        '200':
          description: Mandate retrieved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AllowanceMandate'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '501':
          $ref: '#/components/responses/NotImplemented'
      tags:
      - Mandates
  /mandates/{id}/revoke:
    post:
      operationId: revokeMandate
      summary: Revoke a mandate
      description: Immediately revoke an active or pending_approval mandate. Once revoked, no further credential requests will be accepted. Any virtual cards already issued remain valid until their own expires_at — revocation does not cancel in-flight transactions. Only callable by the mandate owner, not the agent.
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          pattern: ^mnd_
      responses:
        '200':
          description: Mandate revoked
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AllowanceMandate'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '501':
          $ref: '#/components/responses/NotImplemented'
      tags:
      - Mandates
  /mandates/{id}/credential-requests:
    post:
      operationId: requestCredential
      summary: Request a payment credential
      description: 'Request a single-use virtual card to execute a specific purchase against an active mandate. Allowance automatically validates the request against the mandate rules — amount, merchant, merchant category, and time period. No human approval is needed at this step; the human already approved the mandate.


        If validation passes, a virtual card (PAN, expiry, CVV) is returned. The agent uses these details at merchant checkout like a normal card number. The card is single-use, amount-capped, and short-lived — safety comes from these constraints, not from hiding credentials.


        For `cadence: "once"` mandates, the mandate automatically moves to `exhausted` status after the first virtual card is issued.'
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          pattern: ^mnd_
      - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCredentialRequest'
      responses:
        '201':
          description: Credential request processed. Check `validation.passed` for the outcome.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRequest'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          description: Mandate is not active (pending_approval, expired, revoked, or exhausted)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '501':
          $ref: '#/components/responses/NotImplemented'
      x-rate-limit: 10 requests/minute per API key
      tags:
      - Mandates
  /mandates/{id}/credential-requests/{cr_id}:
    get:
      operationId: getCredentialRequest
      summary: Retrieve a credential request
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          pattern: ^mnd_
      - name: cr_id
        in: path
        required: true
        schema:
          type: string
          pattern: ^cr_
      responses:
        '200':
          description: Credential request retrieved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CredentialRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '501':
          $ref: '#/components/responses/NotImplemented'
      tags:
      - Mandates
components:
  responses:
    RateLimited:
      description: Rate limit exceeded
      headers:
        Retry-After:
          schema:
            type: integer
        X-RateLimit-Limit:
          schema:
            type: integer
        X-RateLimit-Remaining:
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotImplemented:
      description: 'Pre-launch: this endpoint is not yet active'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: not_implemented
              message: Allowance is pre-launch. This endpoint is not yet active. Contact hello@useallowance.com for early access.
              doc_url: https://useallowance.com/connect-agent
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    CredentialRequest:
      type: object
      required:
      - id
      - mandate_id
      - amount
      - currency
      - merchant
      - validation
      - status
      - created_at
      properties:
        id:
          type: string
          pattern: ^cr_
          description: Unique credential request ID.
        mandate_id:
          type: string
          pattern: ^mnd_
        amount:
          type: integer
          description: Requested amount in minor currency units.
        currency:
          type: string
        merchant:
          type: string
        merchant_category_code:
          type: string
        context:
          type: string
        idempotency_key:
          type: string
        metadata:
          type: object
          additionalProperties:
            type: string
        validation:
          $ref: '#/components/schemas/ValidationResult'
        virtual_card:
          description: Single-use virtual card if validation passed, null if denied.
          oneOf:
          - $ref: '#/components/schemas/VirtualCard'
          - type: 'null'
        status:
          type: string
          enum:
          - approved
          - denied
          - expired
          description: approved = token issued, proceed with purchase. denied = mandate rules not satisfied, do not proceed. expired = mandate expired before this request was evaluated.
        created_at:
          type: string
          format: date-time
    CreateMandateRequest:
      type: object
      required:
      - agent_id
      - budget
      properties:
        agent_id:
          type: string
        budget:
          $ref: '#/components/schemas/AllowanceBudget'
        risk_controls:
          type: object
          properties:
            require_merchant_match:
              type: boolean
            block_international:
              type: boolean
            max_daily_spend:
              type:
              - integer
              - 'null'
            velocity_limit_per_hour:
              type:
              - integer
              - 'null'
        metadata:
          type: object
          additionalProperties:
            type: string
    CreateCredentialRequest:
      type: object
      required:
      - amount
      - currency
      - merchant
      - context
      properties:
        amount:
          type: integer
          minimum: 1
          description: 'Requested amount in minor currency units (cents). Example: 47231 = $472.31. Never use floats.'
        currency:
          type: string
          pattern: ^[A-Z]{3}$
        merchant:
          type: string
          description: Name of the merchant where the purchase will be made.
        merchant_category_code:
          type: string
          pattern: ^[0-9]{4}$
          description: 4-digit ISO 18245 MCC for the merchant.
        context:
          type: string
          maxLength: 1024
          description: Human-readable explanation of why this purchase is being made. Appears in the owner's transaction log. Be specific — this is the audit trail.
        idempotency_key:
          type: string
          description: Always set this. Prevents duplicate credential issuance on retries.
        metadata:
          type: object
          additionalProperties:
            type: string
    VirtualCard:
      type: object
      description: A single-use virtual card issued when a credential request is approved. The agent uses these details at checkout exactly like a physical card. Safety comes from the card being single-use, amount-capped, merchant-locked, and short-lived — not from hiding credentials.
      required:
      - pan
      - expiry_month
      - expiry_year
      - cvv
      - billing_zip
      - expires_at
      - single_use
      - network
      properties:
        pan:
          type: string
          description: 16-digit card number. Use at merchant checkout.
        expiry_month:
          type: string
          description: '2-digit expiry month. Example: ''09''.'
        expiry_year:
          type: string
          description: '4-digit expiry year. Example: ''2026''.'
        cvv:
          type: string
          description: 3-digit security code.
        billing_zip:
          type: string
          description: Billing ZIP code for AVS verification.
        network:
          type: string
          description: 'Card network. Example: visa, mastercard.'
        expires_at:
          type: string
          format: date-time
          description: When this virtual card expires. Short-lived — use immediately. Typically 15 minutes.
        single_use:
          type: boolean
          description: Always true. This card is deactivated after one approved transaction regardless of cadence.
        amount_limit:
          type: integer
          description: The maximum amount this card will approve, in minor units. Matches the credential request amount. Any charge above this is declined at the network level.
        merchant_lock:
          type:
          - string
          - 'null'
          description: If set, the card is locked to this merchant name. Charges from other merchants are declined at the network level. null if the mandate has no merchant restriction.
    ValidationResult:
      type: object
      required:
      - passed
      - constraints
      - reasons
      description: The system's automatic validation of a credential request against the active mandate rules. No human involvement — this is evaluated instantly.
      properties:
        passed:
          type: boolean
          description: Whether all mandate constraints were satisfied.
        constraints:
          type: object
          description: Individual constraint checks.
          properties:
            within_amount_limit:
              type: object
              properties:
                passed:
                  type: boolean
                detail:
                  type: string
            merchant_match:
              type: object
              properties:
                passed:
                  type: boolean
                detail:
                  type: string
            mcc_match:
              type: object
              properties:
                passed:
                  type: boolean
                detail:
                  type: string
            within_time_period:
              type: object
              properties:
                passed:
                  type: boolean
                detail:
                  type: string
            cadence_not_exhausted:
              type: object
              properties:
                passed:
                  type: boolean
                detail:
                  type: string
            velocity_check:
              type: object
              properties:
                passed:
                  type: boolean
                detail:
                  type: string
        reasons:
          type: array
          items:
            type: string
          description: Human-readable reasons for the validation outcome. Always populated — useful for logging and debugging.
    AllowanceBudget:
      type: object
      required:
      - cadence
      - per_transaction_max
      - currency
      properties:
        cadence:
          type: string
          enum:
          - once
          - daily
          - weekly
          - monthly
          - annually
          - never
          description: Spending cadence. 'once' = single-use mandate — expires after first credential is issued. 'never' = a lifetime cap that never resets. All others reset per interval.
        per_transaction_max:
          type: integer
          minimum: 1
          description: 'Maximum amount per credential request in minor currency units (cents for USD). Example: 50000 = $500.00.'
        total_max:
          type:
          - integer
          - 'null'
          minimum: 1
          description: Total cap across all credential requests in minor units. Resets per cadence interval. null = no cap.
        currency:
          type: string
          pattern: ^[A-Z]{3}$
          description: ISO 4217 currency code.
        merchants:
          type: array
          items:
            type: string
          description: Allowlist of merchant names. Empty array = no merchant restriction.
        merchant_category_codes:
          type: array
          items:
            type: string
            pattern: ^[0-9]{4}$
          description: Allowlist of 4-digit ISO 18245 MCCs. Empty array = no MCC restriction.
        categories:
          type: array
          items:
            type: string
          description: Semantic category labels. Supplementary to MCC — used for display and audit, not enforcement.
        expires_at:
          type:
          - string
          - 'null'
          format: date-time
          description: Mandate expiry as ISO 8601 datetime. null = no expiry. Always set this for sensitive or one-time tasks.
    Error:
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message
          properties:
            code:
              type: string
            message:
              type: string
            param:
              type: string
            doc_url:
              type: string
              format: uri
    AllowanceMandate:
      type: object
      required:
      - id
      - owner_id
      - agent_id
      - budget
      - status
      - created_at
      properties:
        id:
          type: string
          pattern: ^mnd_
          description: Unique mandate ID.
        owner_id:
          type: string
          description: ID of the human user who owns and approved this mandate.
        agent_id:
          type: string
          description: ID of the AI agent authorized to request credentials under this mandate.
        budget:
          $ref: '#/components/schemas/AllowanceBudget'
        risk_controls:
          type: object
          properties:
            require_merchant_match:
              type: boolean
              description: If true, credential requests must exactly match a merchant in the budget.merchants allowlist.
            block_international:
              type: boolean
              description: If true, credential requests for international merchants are denied.
            max_daily_spend:
              type:
              - integer
              - 'null'
              description: Hard daily cap across all credential requests, in minor units.
            velocity_limit_per_hour:
              type:
              - integer
              - 'null'
              description: Maximum number of credential requests allowed per hour.
        status:
          type: string
          enum:
          - pending_approval
          - active
          - exhausted
          - expired
          - revoked
          description: pending_approval = created, awaiting human approval. active = approved, credential requests accepted. exhausted = once mandate fully used. expired = past expires_at. revoked = manually cancelled.
        approved_at:
          type:
          - string
          - 'null'
          format: date-time
          description: When the human owner approved the mandate.
        created_at:
          type: string
          format: date-time
        expires_at:
          type:
          - string
          - 'null'
          format: date-time
        metadata:
          type: object
          additionalProperties:
            type: string
          description: Up to 10 key-value string pairs. Use to record user instruction, task context, etc.
        x-ap2-note:
          type: string
          description: In a future AP2-compatible version, this mandate will be issued as a signed Intent Mandate VDC and approved_at will carry a cryptographic attestation.
  examples:
    FlightMandate:
      summary: Book a flight under $500 (immediate, once)
      value:
        agent_id: agent_claude_travel
        budget:
          cadence: once
          per_transaction_max: 50000
          total_max: 50000
          currency: USD
          merchants:
          - United Airlines
          merchant_category_codes:
          - '4511'
          categories:
          - travel
          - flights
          expires_at: '2026-02-17T14:30:00Z'
        risk_controls:
          require_merchant_match: true
          block_international: false
        metadata:
          task: book cheapest flight to NYC under $500
          initiated_by: user_voice_command
    SubscriptionMandate:
      summary: Pay subscription renewals up to $20/month (recurring, open merchant)
      value:
        agent_id: agent_subscription_manager
        budget:
          cadence: monthly
          per_transaction_max: 2000
          total_max: null
          currency: USD
          merchants: []
          merchant_category_codes:
          - '7372'
          - '7375'
          - '5815'
          categories:
          - subscriptions
          - software
          - streaming
          expires_at: null
        risk_controls:
          block_international: false
          velocity_limit_per_hour: 3
        metadata:
          task: auto-renew approved subscriptions under $20/month
    HouseholdMandate:
      summary: Reorder household item under $40/month (recurring)
      value:
        agent_id: agent_household_reorder
        budget:
          cadence: monthly
          per_transaction_max: 4000
          total_max: null
          currency: USD
          merchants:
          - Amazon
          merchant_category_codes:
          - '5912'
          categories:
          - household
          - consumables
          expires_at: null
        risk_controls:
          require_merchant_match: true
          block_international: true
          velocity_limit_per_hour: 1
        metadata:
          task: reorder paper towels when stock is low
          product_asin: B07N1THQ6Z
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
        maxLength: 255
      description: Client-generated unique key. Same key returns the same response without re-executing the operation. Always set this on credential requests.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Allowance-Key
      description: API key with prefix alw_. Contact hello@useallowance.com for early access.
    OAuth2:
      type: oauth2
      description: OAuth2 authorization code flow (planned — not yet active)
      flows:
        authorizationCode:
          authorizationUrl: https://useallowance.com/oauth/authorize
          tokenUrl: https://useallowance.com/oauth/token
          scopes:
            mandates:write: Propose and manage spending mandates
            mandates:read: Read mandate details and status
            credentials:request: Request payment credentials against active mandates
x-rate-limits:
  standard: 100 requests per minute per API key
  credential_requests_post: 10 requests per minute per API key
  headers:
  - X-RateLimit-Limit
  - X-RateLimit-Remaining
  - X-RateLimit-Reset
x-agent-notes: 'All monetary amounts are integers in minor currency units (cents for USD). Example: 47231 = $472.31. Never use floats. Always set Idempotency-Key on credential requests. Poll GET /v1/mandates/{id} to detect when a mandate moves from pending_approval to active — do not request credentials until the mandate is active.'
x-ap2:
  compatible: true
  mandate_mapping: AllowanceMandate → AP2 Intent Mandate (human-not-present scenario)
  future_changes: Mandate body will be a signed VDC. Human approval will produce a cryptographic attestation. Payment tokens will be AP2 Payment Mandate VDCs.
  spec_url: https://ap2-protocol.org/specification/