openapi: 3.1.0
info:
  title: BAGS Agent API
  version: v1
  description: >-
    BAGS Agent is an agentic-payments API for x402 payment links, products, and
    transaction reads.


    ## Authentication


    Public API endpoints accept either:


    - **API key** in the `Authorization: Bearer <key>` header. Keys are prefixed
      `bag_live_…` and generated from the dashboard. Never expose secret keys
      in client code.
    - **Key scope** — standalone agentic merchants use live keys for
      payment-link management, product management, and transaction reads.
    - **Session cookie** (for dashboard/first-party calls only).


    ## Error shape


    Every non-2xx response is the same envelope:


    ```json

    { "status": "error", "code": "TRANSACTION_DUPLICATE", "message": "…" }

    ```


    Clients MUST switch on `code` (a stable string), not on `message`

    (human-readable, may change). See the `ApiError` schema below for all

    possible codes.


    ## Versioning


    All endpoints documented here live under `/api/v1/`. The unversioned

    `/api/*` shape is an alias kept for backward compatibility — new

    integrations should use `/api/v1/*`. A future `v2` will be introduced

    additively; `v1` stays frozen. See `docs/api-versioning.md` for the

    deprecation policy.


    ## Observability


    Every response carries:


    - `X-Request-ID` — surface this when reporting issues.

    - `X-API-Version` — `v1` or `unversioned`.

    - `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` on
      rate-limited endpoints.
  contact:
    name: BAGS Support
    url: https://www.getbags.app/support
  x-guidance: >-
    BAGS Agent API uses Bearer API keys for product, payment-link, and
    transaction operations. x402 agentic payments are flat per-call USDC on
    /api/agent/link/pl-{paymentLinkId}. GET /api/v1 is a nominal x402 discovery
    index. OpenAPI x-payment-info marks payable routes.
servers:
  - url: https://www.getbags.app
    description: Production
  - url: https://agent-staging.getbags.app
    description: Staging
  - url: http://localhost:3000
    description: Local development
security:
  - apiKey: []
tags:
  - name: Transactions
    description: Recorded payments.
  - name: Payment links
    description: Agentic x402 payment-link endpoints.
  - name: Products
    description: Reusable product catalog entries.
  - name: System
    description: Health, readiness, version.
  - name: x402
    description: Pay-per-call agentic payments (USDC, flat per-call pricing).
externalDocs:
  url: https://docs.getbags.app
  description: Full BAGS documentation
x-build:
  sha: development
  env: development
paths:
  /api/v1/transactions:
    get:
      tags:
        - Transactions
      summary: List transactions
      description: >-
        Returns transactions for the authenticated merchant, newest first.
        Supports cursor pagination via `starting_after`.
      parameters:
        - in: query
          name: limit
          schema:
            description: >-
              Maximum number of items to return. Clamped to [1, 100]; defaults
              to 25.
            example: 25
            type: integer
            minimum: 1
            maximum: 100
          description: >-
            Maximum number of items to return. Clamped to [1, 100]; defaults to
            25.
        - in: query
          name: starting_after
          schema:
            description: Cursor — pass the `id` of the last item from the previous page.
            example: 550e8400-e29b-41d4-a716-446655440000
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          description: Cursor — pass the `id` of the last item from the previous page.
        - in: query
          name: mode
          schema:
            description: >-
              Filter by mode. Defaults to all modes the credential grants access
              to.
            example: test
            type: string
            enum:
              - live
              - test
          description: >-
            Filter by mode. Defaults to all modes the credential grants access
            to.
      responses:
        '200':
          description: Page of transactions.
          content:
            application/json:
              example:
                status: success
                data:
                  - id: 550e8400-e29b-41d4-a716-446655440000
                    amount: 29.99
                    amountBaseUnits: '29990000'
                    token: USDC
                    network: base
                    mode: test
                    livemode: false
                    status: completed
                    txHash: >-
                      0xabcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789
                    walletAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
                    merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                    merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                    paymentLinkId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                    customerEmail: buyer@example.com
                    customerName: Jane Buyer
                    customerAddress: 123 Market St, San Francisco, CA
                    customerCountry: US
                    subtotalAmount: 29.99
                    taxAmount: 0
                    confirmedAt: '2026-04-16T12:34:56.000Z'
                    settledAt: null
                    createdAt: '2026-04-16T12:34:56.000Z'
                    updatedAt: '2026-04-16T12:34:56.000Z'
                hasMore: false
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Transaction'
                  hasMore:
                    type: boolean
                    description: >-
                      True if more results exist beyond the current page. Pass
                      the last returned `id` as `starting_after` to fetch them.
                required:
                  - status
                  - data
                  - hasMore
                additionalProperties: false
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
    post:
      tags:
        - Transactions
      summary: Record a transaction
      description: >-
        Records a completed on-chain transaction. The `txHash` must be unique —
        a second

        call with the same `txHash` returns 409 with `code:
        TRANSACTION_DUPLICATE`.


        Most merchants never need to call this directly — x402 agent settlements
        record

        transactions automatically. Call it yourself only if you are running a
        custom

        payment flow and need to record a completed payment for reconciliation.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                amount:
                  anyOf:
                    - type: string
                    - type: number
                token:
                  type: string
                  enum:
                    - USDC
                    - USDT
                    - SOL
                    - ETH
                    - MATIC
                    - POL
                  example: USDC
                network:
                  type: string
                  enum:
                    - solana
                    - solana_devnet
                    - base
                    - base_sepolia
                    - ethereum
                    - eth_sepolia
                    - polygon
                    - polygon_amoy
                    - arc_testnet
                  example: base
                txHash:
                  type: string
                  minLength: 64
                  maxLength: 128
                  example: >-
                    0xabcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789
                walletAddress:
                  type: string
                  minLength: 32
                  maxLength: 128
                  example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
                status:
                  default: completed
                  type: string
                  enum:
                    - completed
                    - pending
                    - failed
                    - processing
                  example: completed
                customerEmail:
                  type: string
                  maxLength: 320
                customerName:
                  type: string
                  maxLength: 200
                customerAddress:
                  type: string
                  maxLength: 500
                customerCountry:
                  type: string
                  maxLength: 2
                customerState:
                  type: string
                  maxLength: 64
                paymentLinkId:
                  type: string
                  format: uuid
                  pattern: >-
                    ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                  example: 550e8400-e29b-41d4-a716-446655440000
              required:
                - amount
                - token
                - network
                - txHash
                - walletAddress
      responses:
        '201':
          description: Transaction recorded.
          content:
            application/json:
              example:
                status: success
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  amount: 29.99
                  amountBaseUnits: '29990000'
                  token: USDC
                  network: base
                  mode: test
                  livemode: false
                  status: completed
                  txHash: >-
                    0xabcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789
                  walletAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
                  merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                  merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  paymentLinkId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  customerEmail: buyer@example.com
                  customerName: Jane Buyer
                  customerAddress: 123 Market St, San Francisco, CA
                  customerCountry: US
                  subtotalAmount: 29.99
                  taxAmount: 0
                  confirmedAt: '2026-04-16T12:34:56.000Z'
                  settledAt: null
                  createdAt: '2026-04-16T12:34:56.000Z'
                  updatedAt: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                    description: Always "success" on a 2xx response.
                  data:
                    $ref: '#/components/schemas/Transaction'
                required:
                  - status
                  - data
                additionalProperties: false
        '400':
          description: Bad request — the body or query failed validation.
          content:
            application/json:
              example:
                status: error
                code: VALIDATION_FAILED
                message: One or more fields failed validation.
              schema:
                $ref: '#/components/schemas/ApiError'
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '409':
          description: >-
            Duplicate. The response envelope uses `status: "duplicate"` instead
            of `"error"` for backward compatibility, and `code:
            TRANSACTION_DUPLICATE`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: duplicate
                  message:
                    type: string
                required:
                  - status
                  - message
                additionalProperties: false
        '422':
          description: >-
            Unprocessable entity — the request was valid but could not be
            fulfilled.
          content:
            application/json:
              example:
                status: error
                code: TRANSACTION_CHAIN_VERIFY_FAILED
                message: On-chain verification failed for the supplied txHash.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
  /api/v1/transactions/{id}:
    get:
      tags:
        - Transactions
      summary: Retrieve a transaction
      parameters:
        - in: path
          name: id
          schema:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            description: Transaction id.
          required: true
          description: Transaction id.
      responses:
        '200':
          description: The transaction.
          content:
            application/json:
              example:
                status: success
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  amount: 29.99
                  amountBaseUnits: '29990000'
                  token: USDC
                  network: base
                  mode: test
                  livemode: false
                  status: completed
                  txHash: >-
                    0xabcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789
                  walletAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
                  merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                  merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  paymentLinkId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  customerEmail: buyer@example.com
                  customerName: Jane Buyer
                  customerAddress: 123 Market St, San Francisco, CA
                  customerCountry: US
                  subtotalAmount: 29.99
                  taxAmount: 0
                  confirmedAt: '2026-04-16T12:34:56.000Z'
                  settledAt: null
                  createdAt: '2026-04-16T12:34:56.000Z'
                  updatedAt: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                    description: Always "success" on a 2xx response.
                  data:
                    $ref: '#/components/schemas/Transaction'
                required:
                  - status
                  - data
                additionalProperties: false
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: Not found.
          content:
            application/json:
              example:
                status: error
                code: NOT_FOUND
                message: The requested resource was not found.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
  /api/v1/payment-links:
    get:
      tags:
        - Payment links
      summary: List payment links
      parameters:
        - in: query
          name: limit
          schema:
            description: >-
              Maximum number of items to return. Clamped to [1, 100]; defaults
              to 25.
            example: 25
            type: integer
            minimum: 1
            maximum: 100
          description: >-
            Maximum number of items to return. Clamped to [1, 100]; defaults to
            25.
        - in: query
          name: starting_after
          schema:
            description: Cursor — pass the `id` of the last item from the previous page.
            example: 550e8400-e29b-41d4-a716-446655440000
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          description: Cursor — pass the `id` of the last item from the previous page.
      responses:
        '200':
          description: Page of payment links.
          content:
            application/json:
              example:
                status: success
                data:
                  - id: 550e8400-e29b-41d4-a716-446655440000
                    productId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                    name: Pro Plan
                    description: Monthly access to premium features
                    amount: 29.99
                    currency: USD
                    network: base
                    networks:
                      - base
                      - ethereum
                    token: USDC
                    active: true
                    mode: live
                    livemode: true
                    pricingType: one_time
                    billingInterval: null
                    billingIntervalCount: null
                    trialDays: null
                    merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                    merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                    merchantWalletAddresses:
                      base: '0x1111111111111111111111111111111111111111'
                    merchantName: Acme Corp
                    totalCollected: 0
                    totalTransactions: 0
                    customFields: []
                    isAgenticProxy: false
                    targetUrl: null
                    targetMethod: null
                    x402Scheme: exact
                    inputSchema: null
                    inputExample: null
                    successUrl: https://example.com/success
                    returnUrl: https://example.com/return
                    cancelUrl: https://example.com/cancel
                    createdAt: '2026-04-16T12:34:56.000Z'
                    updatedAt: '2026-04-16T12:34:56.000Z'
                hasMore: false
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PaymentLink'
                  hasMore:
                    type: boolean
                    description: >-
                      True if more results exist beyond the current page. Pass
                      the last returned `id` as `starting_after` to fetch them.
                required:
                  - status
                  - data
                  - hasMore
                additionalProperties: false
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
    post:
      tags:
        - Payment links
      summary: Create a payment link
      description: >-
        Creates a reusable payment link. If `productId` is supplied, fields
        default from the product; explicit values always win. Returns 201 with
        the new link.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                productId:
                  type: string
                  format: uuid
                  pattern: >-
                    ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                  example: 550e8400-e29b-41d4-a716-446655440000
                product_id:
                  type: string
                  format: uuid
                  pattern: >-
                    ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                  example: 550e8400-e29b-41d4-a716-446655440000
                syncProduct:
                  type: boolean
                sync_product:
                  type: boolean
                name:
                  type: string
                  maxLength: 200
                description:
                  anyOf:
                    - type: string
                      maxLength: 2000
                    - type: 'null'
                amount:
                  anyOf:
                    - type: string
                    - type: number
                currency:
                  default: USD
                  type: string
                  enum:
                    - USD
                network:
                  type: string
                  enum:
                    - solana
                    - solana_devnet
                    - base
                    - base_sepolia
                    - ethereum
                    - eth_sepolia
                    - polygon
                    - polygon_amoy
                    - arc_testnet
                  example: base
                networks:
                  default: []
                  type: array
                  items:
                    type: string
                    enum:
                      - solana
                      - solana_devnet
                      - base
                      - base_sepolia
                      - ethereum
                      - eth_sepolia
                      - polygon
                      - polygon_amoy
                      - arc_testnet
                    example: base
                token:
                  default: USDC
                  type: string
                  enum:
                    - USDC
                    - USDT
                    - SOL
                    - ETH
                    - MATIC
                    - POL
                  example: USDC
                active:
                  default: true
                  type: boolean
                pricingType:
                  default: one_time
                  example: one_time
                  type: string
                  enum:
                    - one_time
                    - recurring
                pricing_type:
                  default: one_time
                  example: one_time
                  type: string
                  enum:
                    - one_time
                    - recurring
                billingInterval:
                  type: string
                  enum:
                    - minute
                    - week
                    - month
                    - year
                  example: month
                billing_interval:
                  type: string
                  enum:
                    - minute
                    - week
                    - month
                    - year
                  example: month
                billingIntervalCount:
                  type: integer
                  minimum: 1
                  maximum: 12
                billing_interval_count:
                  type: integer
                  minimum: 1
                  maximum: 12
                trialDays:
                  type: integer
                  minimum: 0
                  maximum: 365
                trial_days:
                  type: integer
                  minimum: 0
                  maximum: 365
                merchantWalletAddress:
                  type: string
                  minLength: 32
                  maxLength: 128
                  example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
                merchant_wallet_address:
                  type: string
                  minLength: 32
                  maxLength: 128
                  example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
                merchantWalletAddresses:
                  default: {}
                  type: object
                  propertyNames:
                    type: string
                  additionalProperties:
                    type: string
                    minLength: 32
                    maxLength: 128
                    example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
                merchant_wallet_addresses:
                  type: object
                  propertyNames:
                    type: string
                  additionalProperties:
                    type: string
                    minLength: 32
                    maxLength: 128
                    example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
                merchantName:
                  type: string
                  maxLength: 200
                merchant_name:
                  type: string
                  maxLength: 200
                isAgenticProxy:
                  default: false
                  type: boolean
                is_agentic_proxy:
                  type: boolean
                x402Scheme:
                  type: string
                  enum:
                    - exact
                    - upto
                  example: exact
                x402_scheme:
                  type: string
                  enum:
                    - exact
                    - upto
                  example: exact
                targetUrl:
                  type: string
                  maxLength: 2048
                  format: uri
                target_url:
                  type: string
                  maxLength: 2048
                  format: uri
                targetMethod:
                  type: string
                  enum:
                    - GET
                    - POST
                    - PUT
                    - PATCH
                    - DELETE
                  example: POST
                target_method:
                  type: string
                  enum:
                    - GET
                    - POST
                    - PUT
                    - PATCH
                    - DELETE
                  example: POST
                successUrl:
                  type: string
                  maxLength: 2048
                success_url:
                  type: string
                  maxLength: 2048
                returnUrl:
                  type: string
                  maxLength: 2048
                  format: uri
                return_url:
                  type: string
                  maxLength: 2048
                  format: uri
                cancelUrl:
                  type: string
                  maxLength: 2048
                  format: uri
                cancel_url:
                  type: string
                  maxLength: 2048
                  format: uri
                customFields:
                  maxItems: 20
                  type: array
                  items:
                    type: object
                    properties:
                      key:
                        type: string
                        minLength: 1
                        maxLength: 64
                        pattern: ^[a-z][a-z0-9_]*$
                      label:
                        type: string
                        maxLength: 120
                      type:
                        default: text
                        type: string
                        enum:
                          - text
                          - email
                          - textarea
                          - select
                          - checkbox
                      required:
                        default: false
                        type: boolean
                      placeholder:
                        anyOf:
                          - type: string
                            maxLength: 200
                          - type: 'null'
                      helpText:
                        anyOf:
                          - type: string
                            maxLength: 240
                          - type: 'null'
                      maxLength:
                        type: integer
                        minimum: 1
                        maximum: 4000
                      options:
                        maxItems: 32
                        type: array
                        items:
                          type: object
                          properties:
                            value:
                              type: string
                              minLength: 1
                              maxLength: 120
                            label:
                              type: string
                              maxLength: 120
                          required:
                            - value
                            - label
                    required:
                      - key
                      - label
                custom_fields:
                  maxItems: 20
                  type: array
                  items:
                    type: object
                    properties:
                      key:
                        type: string
                        minLength: 1
                        maxLength: 64
                        pattern: ^[a-z][a-z0-9_]*$
                      label:
                        type: string
                        maxLength: 120
                      type:
                        default: text
                        type: string
                        enum:
                          - text
                          - email
                          - textarea
                          - select
                          - checkbox
                      required:
                        default: false
                        type: boolean
                      placeholder:
                        anyOf:
                          - type: string
                            maxLength: 200
                          - type: 'null'
                      helpText:
                        anyOf:
                          - type: string
                            maxLength: 240
                          - type: 'null'
                      maxLength:
                        type: integer
                        minimum: 1
                        maximum: 4000
                      options:
                        maxItems: 32
                        type: array
                        items:
                          type: object
                          properties:
                            value:
                              type: string
                              minLength: 1
                              maxLength: 120
                            label:
                              type: string
                              maxLength: 120
                          required:
                            - value
                            - label
                    required:
                      - key
                      - label
                inputSchema:
                  type: object
                  properties:
                    type:
                      type: string
                      const: object
                    additionalProperties:
                      type: boolean
                    properties:
                      type: object
                      propertyNames:
                        type: string
                        maxLength: 64
                        pattern: ^[a-zA-Z][a-zA-Z0-9_]*$
                      additionalProperties:
                        type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - string
                              - number
                              - integer
                              - boolean
                              - array
                              - object
                          description:
                            type: string
                            maxLength: 500
                          enum:
                            maxItems: 32
                            type: array
                            items:
                              type: string
                              maxLength: 120
                          format:
                            type: string
                            maxLength: 64
                          items:
                            type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - string
                                  - number
                                  - integer
                                  - boolean
                                  - array
                                  - object
                            required:
                              - type
                          example: {}
                          default: {}
                          minimum:
                            type: number
                          maximum:
                            type: number
                          minLength:
                            type: integer
                            minimum: 0
                            maximum: 9007199254740991
                          maxLength:
                            type: integer
                            minimum: 1
                            maximum: 9007199254740991
                        required:
                          - type
                        additionalProperties: false
                    required:
                      maxItems: 20
                      type: array
                      items:
                        type: string
                        maxLength: 64
                  required:
                    - properties
                  additionalProperties: false
                input_schema:
                  type: object
                  properties:
                    type:
                      type: string
                      const: object
                    additionalProperties:
                      type: boolean
                    properties:
                      type: object
                      propertyNames:
                        type: string
                        maxLength: 64
                        pattern: ^[a-zA-Z][a-zA-Z0-9_]*$
                      additionalProperties:
                        type: object
                        properties:
                          type:
                            type: string
                            enum:
                              - string
                              - number
                              - integer
                              - boolean
                              - array
                              - object
                          description:
                            type: string
                            maxLength: 500
                          enum:
                            maxItems: 32
                            type: array
                            items:
                              type: string
                              maxLength: 120
                          format:
                            type: string
                            maxLength: 64
                          items:
                            type: object
                            properties:
                              type:
                                type: string
                                enum:
                                  - string
                                  - number
                                  - integer
                                  - boolean
                                  - array
                                  - object
                            required:
                              - type
                          example: {}
                          default: {}
                          minimum:
                            type: number
                          maximum:
                            type: number
                          minLength:
                            type: integer
                            minimum: 0
                            maximum: 9007199254740991
                          maxLength:
                            type: integer
                            minimum: 1
                            maximum: 9007199254740991
                        required:
                          - type
                        additionalProperties: false
                    required:
                      maxItems: 20
                      type: array
                      items:
                        type: string
                        maxLength: 64
                  required:
                    - properties
                  additionalProperties: false
                inputExample:
                  type: object
                  propertyNames:
                    type: string
                    maxLength: 64
                  additionalProperties: {}
                input_example:
                  type: object
                  propertyNames:
                    type: string
                    maxLength: 64
                  additionalProperties: {}
              required:
                - network
      responses:
        '201':
          description: Created.
          content:
            application/json:
              example:
                status: success
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  productId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  name: Pro Plan
                  description: Monthly access to premium features
                  amount: 29.99
                  currency: USD
                  network: base
                  networks:
                    - base
                    - ethereum
                  token: USDC
                  active: true
                  mode: live
                  livemode: true
                  pricingType: one_time
                  billingInterval: null
                  billingIntervalCount: null
                  trialDays: null
                  merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                  merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  merchantWalletAddresses:
                    base: '0x1111111111111111111111111111111111111111'
                  merchantName: Acme Corp
                  totalCollected: 0
                  totalTransactions: 0
                  customFields: []
                  isAgenticProxy: false
                  targetUrl: null
                  targetMethod: null
                  x402Scheme: exact
                  inputSchema: null
                  inputExample: null
                  successUrl: https://example.com/success
                  returnUrl: https://example.com/return
                  cancelUrl: https://example.com/cancel
                  createdAt: '2026-04-16T12:34:56.000Z'
                  updatedAt: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                    description: Always "success" on a 2xx response.
                  data:
                    $ref: '#/components/schemas/PaymentLink'
                required:
                  - status
                  - data
                additionalProperties: false
        '400':
          description: Bad request — the body or query failed validation.
          content:
            application/json:
              example:
                status: error
                code: VALIDATION_FAILED
                message: One or more fields failed validation.
              schema:
                $ref: '#/components/schemas/ApiError'
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: >-
            Not found — the resource does not exist or is hidden from the
            caller.
          content:
            application/json:
              example:
                status: error
                code: NOT_FOUND
                message: The requested resource was not found.
              schema:
                $ref: '#/components/schemas/ApiError'
        '422':
          description: >-
            Unprocessable entity — the request was valid but could not be
            fulfilled.
          content:
            application/json:
              example:
                status: error
                code: TRANSACTION_CHAIN_VERIFY_FAILED
                message: On-chain verification failed for the supplied txHash.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
  /api/v1/payment-links/{id}:
    get:
      tags:
        - Payment links
      summary: Retrieve a payment link
      parameters:
        - in: path
          name: id
          schema:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            description: Payment link id.
          required: true
          description: Payment link id.
      responses:
        '200':
          description: The payment link.
          content:
            application/json:
              example:
                status: success
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  productId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  name: Pro Plan
                  description: Monthly access to premium features
                  amount: 29.99
                  currency: USD
                  network: base
                  networks:
                    - base
                    - ethereum
                  token: USDC
                  active: true
                  mode: live
                  livemode: true
                  pricingType: one_time
                  billingInterval: null
                  billingIntervalCount: null
                  trialDays: null
                  merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                  merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  merchantWalletAddresses:
                    base: '0x1111111111111111111111111111111111111111'
                  merchantName: Acme Corp
                  totalCollected: 0
                  totalTransactions: 0
                  customFields: []
                  isAgenticProxy: false
                  targetUrl: null
                  targetMethod: null
                  x402Scheme: exact
                  inputSchema: null
                  inputExample: null
                  successUrl: https://example.com/success
                  returnUrl: https://example.com/return
                  cancelUrl: https://example.com/cancel
                  createdAt: '2026-04-16T12:34:56.000Z'
                  updatedAt: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                    description: Always "success" on a 2xx response.
                  data:
                    $ref: '#/components/schemas/PaymentLink'
                required:
                  - status
                  - data
                additionalProperties: false
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: >-
            Not found — the resource does not exist or is hidden from the
            caller.
          content:
            application/json:
              example:
                status: error
                code: NOT_FOUND
                message: The requested resource was not found.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
    patch:
      tags:
        - Payment links
      summary: Update a payment link
      parameters:
        - in: path
          name: id
          schema:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            description: Payment link id.
          required: true
          description: Payment link id.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                active:
                  type: boolean
                amount:
                  anyOf:
                    - type: string
                    - type: number
      responses:
        '200':
          description: Updated.
          content:
            application/json:
              example:
                status: success
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  productId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  name: Pro Plan
                  description: Monthly access to premium features
                  amount: 29.99
                  currency: USD
                  network: base
                  networks:
                    - base
                    - ethereum
                  token: USDC
                  active: true
                  mode: live
                  livemode: true
                  pricingType: one_time
                  billingInterval: null
                  billingIntervalCount: null
                  trialDays: null
                  merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                  merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  merchantWalletAddresses:
                    base: '0x1111111111111111111111111111111111111111'
                  merchantName: Acme Corp
                  totalCollected: 0
                  totalTransactions: 0
                  customFields: []
                  isAgenticProxy: false
                  targetUrl: null
                  targetMethod: null
                  x402Scheme: exact
                  inputSchema: null
                  inputExample: null
                  successUrl: https://example.com/success
                  returnUrl: https://example.com/return
                  cancelUrl: https://example.com/cancel
                  createdAt: '2026-04-16T12:34:56.000Z'
                  updatedAt: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                    description: Always "success" on a 2xx response.
                  data:
                    $ref: '#/components/schemas/PaymentLink'
                required:
                  - status
                  - data
                additionalProperties: false
        '400':
          description: Bad request — the body or query failed validation.
          content:
            application/json:
              example:
                status: error
                code: VALIDATION_FAILED
                message: One or more fields failed validation.
              schema:
                $ref: '#/components/schemas/ApiError'
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: >-
            Not found — the resource does not exist or is hidden from the
            caller.
          content:
            application/json:
              example:
                status: error
                code: NOT_FOUND
                message: The requested resource was not found.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
    delete:
      tags:
        - Payment links
      summary: Archive a payment link
      description: >-
        Payment links are archived rather than hard-deleted so existing links in
        the wild still resolve to a "this link is no longer active" page.
      parameters:
        - in: path
          name: id
          schema:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            description: Payment link id.
          required: true
          description: Payment link id.
      responses:
        '204':
          description: Archived.
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: >-
            Not found — the resource does not exist or is hidden from the
            caller.
          content:
            application/json:
              example:
                status: error
                code: NOT_FOUND
                message: The requested resource was not found.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
  /api/v1/products:
    get:
      tags:
        - Products
      summary: List products
      parameters:
        - in: query
          name: limit
          schema:
            description: >-
              Maximum number of items to return. Clamped to [1, 100]; defaults
              to 25.
            example: 25
            type: integer
            minimum: 1
            maximum: 100
          description: >-
            Maximum number of items to return. Clamped to [1, 100]; defaults to
            25.
        - in: query
          name: starting_after
          schema:
            description: Cursor — pass the `id` of the last item from the previous page.
            example: 550e8400-e29b-41d4-a716-446655440000
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          description: Cursor — pass the `id` of the last item from the previous page.
      responses:
        '200':
          description: Page of products.
          content:
            application/json:
              example:
                status: success
                data:
                  - id: 550e8400-e29b-41d4-a716-446655440000
                    name: Pro Plan
                    description: Monthly access to premium features
                    amount: 29.99
                    currency: USD
                    active: true
                    archived: false
                    mode: live
                    pricingType: recurring
                    billingInterval: month
                    billingIntervalCount: 1
                    trialDays: 14
                    token: USDC
                    merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                    merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                    metadata: {}
                    totalCollected: 0
                    totalTransactions: 0
                    createdAt: '2026-04-16T12:34:56.000Z'
                    updatedAt: '2026-04-16T12:34:56.000Z'
                hasMore: false
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Product'
                  hasMore:
                    type: boolean
                    description: >-
                      True if more results exist beyond the current page. Pass
                      the last returned `id` as `starting_after` to fetch them.
                required:
                  - status
                  - data
                  - hasMore
                additionalProperties: false
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
    post:
      tags:
        - Products
      summary: Create a product
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 200
                description:
                  anyOf:
                    - type: string
                      maxLength: 2000
                    - type: 'null'
                amount:
                  anyOf:
                    - type: string
                    - type: number
                currency:
                  default: USD
                  type: string
                  enum:
                    - USD
                pricingType:
                  default: one_time
                  example: one_time
                  type: string
                  enum:
                    - one_time
                    - recurring
                pricing_type:
                  default: one_time
                  example: one_time
                  type: string
                  enum:
                    - one_time
                    - recurring
                billingInterval:
                  type: string
                  enum:
                    - minute
                    - week
                    - month
                    - year
                  example: month
                billing_interval:
                  type: string
                  enum:
                    - minute
                    - week
                    - month
                    - year
                  example: month
                billingIntervalCount:
                  type: integer
                  minimum: 1
                  maximum: 12
                billing_interval_count:
                  type: integer
                  minimum: 1
                  maximum: 12
                trialDays:
                  type: integer
                  minimum: 0
                  maximum: 365
                trial_days:
                  type: integer
                  minimum: 0
                  maximum: 365
                token:
                  default: USDC
                  type: string
                  enum:
                    - USDC
                    - USDT
                    - SOL
                    - ETH
                    - MATIC
                    - POL
                  example: USDC
                merchantWalletAddress:
                  type: string
                  minLength: 32
                  maxLength: 128
                  example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
                merchant_wallet_address:
                  type: string
                  minLength: 32
                  maxLength: 128
                  example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
                mode:
                  type: string
                  enum:
                    - live
                    - test
              required:
                - name
                - amount
      responses:
        '201':
          description: Created.
          content:
            application/json:
              example:
                status: success
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  name: Pro Plan
                  description: Monthly access to premium features
                  amount: 29.99
                  currency: USD
                  active: true
                  archived: false
                  mode: live
                  pricingType: recurring
                  billingInterval: month
                  billingIntervalCount: 1
                  trialDays: 14
                  token: USDC
                  merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                  merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  metadata: {}
                  totalCollected: 0
                  totalTransactions: 0
                  createdAt: '2026-04-16T12:34:56.000Z'
                  updatedAt: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                    description: Always "success" on a 2xx response.
                  data:
                    $ref: '#/components/schemas/Product'
                required:
                  - status
                  - data
                additionalProperties: false
        '400':
          description: Bad request — the body or query failed validation.
          content:
            application/json:
              example:
                status: error
                code: VALIDATION_FAILED
                message: One or more fields failed validation.
              schema:
                $ref: '#/components/schemas/ApiError'
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '422':
          description: >-
            Unprocessable entity — the request was valid but could not be
            fulfilled.
          content:
            application/json:
              example:
                status: error
                code: TRANSACTION_CHAIN_VERIFY_FAILED
                message: On-chain verification failed for the supplied txHash.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
  /api/v1/products/{id}:
    get:
      tags:
        - Products
      summary: Retrieve a product
      parameters:
        - in: path
          name: id
          schema:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            description: Product id.
          required: true
          description: Product id.
      responses:
        '200':
          description: The product.
          content:
            application/json:
              example:
                status: success
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  name: Pro Plan
                  description: Monthly access to premium features
                  amount: 29.99
                  currency: USD
                  active: true
                  archived: false
                  mode: live
                  pricingType: recurring
                  billingInterval: month
                  billingIntervalCount: 1
                  trialDays: 14
                  token: USDC
                  merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                  merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  metadata: {}
                  totalCollected: 0
                  totalTransactions: 0
                  createdAt: '2026-04-16T12:34:56.000Z'
                  updatedAt: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                    description: Always "success" on a 2xx response.
                  data:
                    $ref: '#/components/schemas/Product'
                required:
                  - status
                  - data
                additionalProperties: false
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: >-
            Not found — the resource does not exist or is hidden from the
            caller.
          content:
            application/json:
              example:
                status: error
                code: NOT_FOUND
                message: The requested resource was not found.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
    patch:
      tags:
        - Products
      summary: Update a product
      parameters:
        - in: path
          name: id
          schema:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            description: Product id.
          required: true
          description: Product id.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 200
                description:
                  anyOf:
                    - type: string
                      maxLength: 2000
                    - type: 'null'
                amount:
                  anyOf:
                    - type: string
                    - type: number
                active:
                  type: boolean
                pricingType:
                  default: one_time
                  example: one_time
                  type: string
                  enum:
                    - one_time
                    - recurring
                billingInterval:
                  type: string
                  enum:
                    - minute
                    - week
                    - month
                    - year
                  example: month
                billingIntervalCount:
                  type: integer
                  minimum: 1
                  maximum: 12
                trialDays:
                  type: integer
                  minimum: 0
                  maximum: 365
      responses:
        '200':
          description: Updated.
          content:
            application/json:
              example:
                status: success
                data:
                  id: 550e8400-e29b-41d4-a716-446655440000
                  name: Pro Plan
                  description: Monthly access to premium features
                  amount: 29.99
                  currency: USD
                  active: true
                  archived: false
                  mode: live
                  pricingType: recurring
                  billingInterval: month
                  billingIntervalCount: 1
                  trialDays: 14
                  token: USDC
                  merchantWalletAddress: '0x1111111111111111111111111111111111111111'
                  merchantId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8
                  metadata: {}
                  totalCollected: 0
                  totalTransactions: 0
                  createdAt: '2026-04-16T12:34:56.000Z'
                  updatedAt: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: success
                    description: Always "success" on a 2xx response.
                  data:
                    $ref: '#/components/schemas/Product'
                required:
                  - status
                  - data
                additionalProperties: false
        '400':
          description: Bad request — the body or query failed validation.
          content:
            application/json:
              example:
                status: error
                code: VALIDATION_FAILED
                message: One or more fields failed validation.
              schema:
                $ref: '#/components/schemas/ApiError'
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: >-
            Not found — the resource does not exist or is hidden from the
            caller.
          content:
            application/json:
              example:
                status: error
                code: NOT_FOUND
                message: The requested resource was not found.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
    delete:
      tags:
        - Products
      summary: Archive a product
      parameters:
        - in: path
          name: id
          schema:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            description: Product id.
          required: true
          description: Product id.
      responses:
        '204':
          description: Archived.
        '401':
          description: Unauthorized — no valid API key or session token was presented.
          content:
            application/json:
              example:
                status: error
                code: AUTH_MISSING_CREDENTIALS
                message: No API key or session token was provided.
                hint: >-
                  Include a valid API key in the Authorization header: Bearer
                  bag_live_sk_...
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: Forbidden — the credential is valid but does not grant access.
          content:
            application/json:
              example:
                status: error
                code: AUTH_TENANT_MISMATCH
                message: The credential does not grant access to this resource.
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: >-
            Not found — the resource does not exist or is hidden from the
            caller.
          content:
            application/json:
              example:
                status: error
                code: NOT_FOUND
                message: The requested resource was not found.
              schema:
                $ref: '#/components/schemas/ApiError'
        '429':
          description: Rate limited — the caller is sending too many requests.
          content:
            application/json:
              example:
                status: error
                code: RATE_LIMITED
                message: Too many requests. Back off and retry.
                retryAfter: 60
              schema:
                $ref: '#/components/schemas/ApiError'
        '500':
          description: Internal error — an unexpected failure occurred.
          content:
            application/json:
              example:
                status: error
                code: INTERNAL_ERROR
                message: An unexpected error occurred. The incident has been logged.
              schema:
                $ref: '#/components/schemas/ApiError'
  /api/health:
    get:
      tags:
        - System
      summary: Liveness probe
      description: >-
        Cheap check that the worker is alive. Does NOT touch the database — use
        `/api/ready` for that.
      responses:
        '200':
          description: Alive.
          content:
            application/json:
              example:
                status: ok
                sha: c866862e
                env: production
                timestamp: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    const: ok
                  sha:
                    type: string
                    description: Short build SHA.
                    example: c866862e
                  env:
                    type: string
                    description: Deployment tier (production, staging, development, …).
                    example: production
                  timestamp:
                    type: string
                    description: ISO 8601 timestamp when the probe was served.
                    example: '2026-04-16T12:34:56.000Z'
                required:
                  - status
                  - sha
                  - env
                  - timestamp
                additionalProperties: false
  /api/ready:
    get:
      tags:
        - System
      summary: Readiness probe
      description: >-
        Verifies the worker can serve traffic — runs a cheap `SELECT 1` against
        the database. Returns 503 if any dependency is unhealthy.
      responses:
        '200':
          description: Ready to serve traffic.
          content:
            application/json:
              example:
                status: ready
                sha: c866862e
                env: production
                checks:
                  database:
                    ok: true
                    latencyMs: 12
                latencyMs: 13
                timestamp: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - ready
                      - not_ready
                    example: ready
                  sha:
                    type: string
                    description: Short build SHA.
                    example: c866862e
                  env:
                    type: string
                    description: Deployment tier.
                    example: production
                  checks:
                    type: object
                    properties:
                      database:
                        type: object
                        properties:
                          ok:
                            type: boolean
                            example: true
                          latencyMs:
                            type: number
                            example: 12
                        required:
                          - ok
                          - latencyMs
                        additionalProperties: false
                    required:
                      - database
                    additionalProperties: false
                  latencyMs:
                    type: number
                    description: >-
                      Total time spent running all dependency checks, in
                      milliseconds.
                    example: 1
                  timestamp:
                    type: string
                    description: ISO 8601 timestamp when the probe was served.
                    example: '2026-04-16T12:34:56.000Z'
                required:
                  - status
                  - sha
                  - env
                  - checks
                  - latencyMs
                  - timestamp
                additionalProperties: false
        '503':
          description: Not ready — a dependency check failed.
          content:
            application/json:
              example:
                status: not_ready
                sha: c866862e
                env: production
                checks:
                  database:
                    ok: false
                    latencyMs: 5000
                latencyMs: 5001
                timestamp: '2026-04-16T12:34:56.000Z'
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - ready
                      - not_ready
                    example: ready
                  sha:
                    type: string
                    description: Short build SHA.
                    example: c866862e
                  env:
                    type: string
                    description: Deployment tier.
                    example: production
                  checks:
                    type: object
                    properties:
                      database:
                        type: object
                        properties:
                          ok:
                            type: boolean
                            example: true
                          latencyMs:
                            type: number
                            example: 12
                        required:
                          - ok
                          - latencyMs
                        additionalProperties: false
                    required:
                      - database
                    additionalProperties: false
                  latencyMs:
                    type: number
                    description: >-
                      Total time spent running all dependency checks, in
                      milliseconds.
                    example: 1
                  timestamp:
                    type: string
                    description: ISO 8601 timestamp when the probe was served.
                    example: '2026-04-16T12:34:56.000Z'
                required:
                  - status
                  - sha
                  - env
                  - checks
                  - latencyMs
                  - timestamp
                additionalProperties: false
  /api/version:
    get:
      tags:
        - System
      summary: Build metadata
      description: >-
        Returns build metadata (SHA, build time, deployment tier). Useful for
        support and for verifying which build is serving traffic.
      responses:
        '200':
          description: Build metadata.
          content:
            application/json:
              example:
                name: bags-api
                apiVersion: v1
                sha: c866862e
                buildTime: '2026-04-16T12:34:56.000Z'
                env: production
                releaseId: production@c866862e
              schema:
                type: object
                properties:
                  name:
                    type: string
                    const: bags-api
                    description: Service identifier.
                  apiVersion:
                    type: string
                    const: v1
                    description: Stable public API version.
                  sha:
                    type: string
                    description: Short build SHA.
                    example: c866862e
                  buildTime:
                    type: string
                    description: ISO 8601 build timestamp.
                    example: '2026-04-16T12:34:56.000Z'
                  env:
                    type: string
                    description: Deployment tier (production, staging, development, …).
                    example: production
                  releaseId:
                    type: string
                    description: >-
                      Short identifier combining env and SHA, e.g.
                      `production@c866862e`.
                    example: production@c866862e
                required:
                  - name
                  - apiVersion
                  - sha
                  - buildTime
                  - env
                  - releaseId
                additionalProperties: false
  /api/v1:
    get:
      tags:
        - x402
      summary: BAGS Agent API index (x402 discovery)
      description: >-
        Machine-readable directory of the BAGS Agent API, MCP server, and x402
        payment surface. Returns 402 with a nominal USDC challenge when unpaid.
      security: []
      x-payment-info:
        price:
          mode: fixed
          currency: USD
          amount: '0.01'
        protocols:
          - x402: {}
      parameters:
        - name: PAYMENT-SIGNATURE
          in: header
          required: false
          description: >-
            x402 payment payload (base64). Required to settle a 402 challenge.
            v1 clients may send `x-payment` instead.
          schema:
            type: string
      responses:
        '200':
          description: API index after successful x402 payment.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/X402ApiV1Index'
        '402':
          description: >-
            Payment Required — x402 payment requirements in the
            `PAYMENT-REQUIRED` response header (and mirrored in the JSON body).
  /api/agent/link/{paymentLinkId}:
    get:
      tags:
        - x402
      summary: Agentic proxy (GET)
      description: >-
        x402 agentic payment proxy. Returns 402 with USDC payment requirements
        when unpaid; proxies to the merchant `targetUrl` after settlement. No
        buyer details collected — flat per-call pricing from the payment link.
      security: []
      x-payment-info:
        price:
          mode: dynamic
          currency: USD
          min: '0.01'
          max: '100000'
        protocols:
          - x402: {}
      parameters:
        - in: path
          name: paymentLinkId
          schema:
            type: string
            description: >-
              Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
              `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are
              accepted.
            example: pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890
          required: true
          description: >-
            Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
            `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are accepted.
        - name: PAYMENT-SIGNATURE
          in: header
          required: false
          description: >-
            x402 payment payload (base64). Required to settle a 402 challenge.
            v1 clients may send `x-payment` instead.
          schema:
            type: string
      responses:
        '200':
          description: Proxied upstream response after successful x402 settlement.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/X402AgentProxyResponse'
        '402':
          description: >-
            Payment Required — x402 payment requirements in the
            `PAYMENT-REQUIRED` response header (and mirrored in the JSON body).
        '404':
          description: Payment link not found or agentic proxy disabled.
    post:
      tags:
        - x402
      summary: Agentic proxy (POST)
      description: >-
        x402 agentic payment proxy. Returns 402 with USDC payment requirements
        when unpaid; proxies to the merchant `targetUrl` after settlement. No
        buyer details collected — flat per-call pricing from the payment link.
      security: []
      x-payment-info:
        price:
          mode: dynamic
          currency: USD
          min: '0.01'
          max: '100000'
        protocols:
          - x402: {}
      parameters:
        - in: path
          name: paymentLinkId
          schema:
            type: string
            description: >-
              Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
              `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are
              accepted.
            example: pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890
          required: true
          description: >-
            Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
            `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are accepted.
        - name: PAYMENT-SIGNATURE
          in: header
          required: false
          description: >-
            x402 payment payload (base64). Required to settle a 402 challenge.
            v1 clients may send `x-payment` instead.
          schema:
            type: string
      responses:
        '200':
          description: Proxied upstream response after successful x402 settlement.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/X402AgentProxyResponse'
        '402':
          description: >-
            Payment Required — x402 payment requirements in the
            `PAYMENT-REQUIRED` response header (and mirrored in the JSON body).
        '404':
          description: Payment link not found or agentic proxy disabled.
    put:
      tags:
        - x402
      summary: Agentic proxy (PUT)
      description: >-
        x402 agentic payment proxy. Returns 402 with USDC payment requirements
        when unpaid; proxies to the merchant `targetUrl` after settlement. No
        buyer details collected — flat per-call pricing from the payment link.
      security: []
      x-payment-info:
        price:
          mode: dynamic
          currency: USD
          min: '0.01'
          max: '100000'
        protocols:
          - x402: {}
      parameters:
        - in: path
          name: paymentLinkId
          schema:
            type: string
            description: >-
              Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
              `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are
              accepted.
            example: pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890
          required: true
          description: >-
            Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
            `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are accepted.
        - name: PAYMENT-SIGNATURE
          in: header
          required: false
          description: >-
            x402 payment payload (base64). Required to settle a 402 challenge.
            v1 clients may send `x-payment` instead.
          schema:
            type: string
      responses:
        '200':
          description: Proxied upstream response after successful x402 settlement.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/X402AgentProxyResponse'
        '402':
          description: >-
            Payment Required — x402 payment requirements in the
            `PAYMENT-REQUIRED` response header (and mirrored in the JSON body).
        '404':
          description: Payment link not found or agentic proxy disabled.
    patch:
      tags:
        - x402
      summary: Agentic proxy (PATCH)
      description: >-
        x402 agentic payment proxy. Returns 402 with USDC payment requirements
        when unpaid; proxies to the merchant `targetUrl` after settlement. No
        buyer details collected — flat per-call pricing from the payment link.
      security: []
      x-payment-info:
        price:
          mode: dynamic
          currency: USD
          min: '0.01'
          max: '100000'
        protocols:
          - x402: {}
      parameters:
        - in: path
          name: paymentLinkId
          schema:
            type: string
            description: >-
              Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
              `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are
              accepted.
            example: pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890
          required: true
          description: >-
            Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
            `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are accepted.
        - name: PAYMENT-SIGNATURE
          in: header
          required: false
          description: >-
            x402 payment payload (base64). Required to settle a 402 challenge.
            v1 clients may send `x-payment` instead.
          schema:
            type: string
      responses:
        '200':
          description: Proxied upstream response after successful x402 settlement.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/X402AgentProxyResponse'
        '402':
          description: >-
            Payment Required — x402 payment requirements in the
            `PAYMENT-REQUIRED` response header (and mirrored in the JSON body).
        '404':
          description: Payment link not found or agentic proxy disabled.
    delete:
      tags:
        - x402
      summary: Agentic proxy (DELETE)
      description: >-
        x402 agentic payment proxy. Returns 402 with USDC payment requirements
        when unpaid; proxies to the merchant `targetUrl` after settlement. No
        buyer details collected — flat per-call pricing from the payment link.
      security: []
      x-payment-info:
        price:
          mode: dynamic
          currency: USD
          min: '0.01'
          max: '100000'
        protocols:
          - x402: {}
      parameters:
        - in: path
          name: paymentLinkId
          schema:
            type: string
            description: >-
              Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
              `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are
              accepted.
            example: pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890
          required: true
          description: >-
            Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
            `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are accepted.
        - name: PAYMENT-SIGNATURE
          in: header
          required: false
          description: >-
            x402 payment payload (base64). Required to settle a 402 challenge.
            v1 clients may send `x-payment` instead.
          schema:
            type: string
      responses:
        '200':
          description: Proxied upstream response after successful x402 settlement.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/X402AgentProxyResponse'
        '402':
          description: >-
            Payment Required — x402 payment requirements in the
            `PAYMENT-REQUIRED` response header (and mirrored in the JSON body).
        '404':
          description: Payment link not found or agentic proxy disabled.
  /api/agent/{id}:
    get:
      tags:
        - x402
      summary: Agentic proxy alias (GET)
      description: >-
        x402 agentic payment proxy. Returns 402 with USDC payment requirements
        when unpaid; proxies to the merchant `targetUrl` after settlement. No
        buyer details collected — flat per-call pricing from the payment link.
      security: []
      x-payment-info:
        price:
          mode: dynamic
          currency: USD
          min: '0.01'
          max: '100000'
        protocols:
          - x402: {}
      parameters:
        - in: path
          name: id
          schema:
            type: string
            format: uuid
            pattern: >-
              ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
            description: Payment link UUID (legacy alias path).
            example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
          required: true
          description: Payment link UUID (legacy alias path).
        - name: PAYMENT-SIGNATURE
          in: header
          required: false
          description: >-
            x402 payment payload (base64). Required to settle a 402 challenge.
            v1 clients may send `x-payment` instead.
          schema:
            type: string
      responses:
        '200':
          description: Proxied upstream response after successful x402 settlement.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/X402AgentProxyResponse'
        '402':
          description: >-
            Payment Required — x402 payment requirements in the
            `PAYMENT-REQUIRED` response header (and mirrored in the JSON body).
        '404':
          description: Payment link not found or agentic proxy disabled.
  /api/agent/link/{paymentLinkId}/price:
    get:
      tags:
        - x402
      summary: Agentic link price discovery
      description: >-
        Read-only rate card for an agentic payment link — price, network, and
        x402 scheme WITHOUT triggering a 402 challenge. Mirrors the 402
        challenge body (minus `payTo`, which is issued at pay time). Free; no
        auth.
      security: []
      parameters:
        - in: path
          name: paymentLinkId
          schema:
            type: string
            description: >-
              Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
              `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are
              accepted.
            example: pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890
          required: true
          description: >-
            Payment link id. Prefer the canonical `pl-{uuid}` form (e.g.
            `pl-a1b2c3d4-e5f6-7890-abcd-ef1234567890`); bare UUIDs are accepted.
      responses:
        '200':
          description: The link's price, network, scheme, and quote.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/X402AgentPrice'
        '404':
          description: Payment link not found or inactive.
  /api/agent/receipt/{txHash}:
    get:
      tags:
        - x402
      summary: x402 payment receipt by tx hash
      description: >-
        Buyer-visible receipt for a settled x402 agent payment, keyed on the
        on-chain transaction hash. Exposes only on-chain-public data plus
        settlement status (`payment_receipt` with tx hash + correlation id).
        Free; no auth.
      security: []
      parameters:
        - in: path
          name: txHash
          schema:
            type: string
            description: >-
              On-chain transaction hash (EVM 0x-hash or Solana signature) of a
              settled x402 payment.
            example: '0x1111111111111111111111111111111111111111111111111111111111111111'
          required: true
          description: >-
            On-chain transaction hash (EVM 0x-hash or Solana signature) of a
            settled x402 payment.
      responses:
        '200':
          description: The payment receipt.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/X402PaymentReceipt'
        '404':
          description: No x402 payment recorded for this tx hash.
components:
  schemas:
    Transaction:
      type: object
      properties:
        id:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          example: 550e8400-e29b-41d4-a716-446655440000
          description: Server-generated transaction id.
        amount:
          type: number
          description: >-
            USD price as a JSON number. Product and payment-link prices support
            up to 4 decimal places in storage.
          example: 19.9999
        amountBaseUnits:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            On-chain transfer amount in base units, serialized as a decimal
            string.
        token:
          type: string
          enum:
            - USDC
            - USDT
            - SOL
            - ETH
            - MATIC
            - POL
          example: USDC
        network:
          type: string
          enum:
            - solana
            - solana_devnet
            - base
            - base_sepolia
            - ethereum
            - eth_sepolia
            - polygon
            - polygon_amoy
            - arc_testnet
          example: base
        mode:
          type: string
          enum:
            - live
            - test
          description: Which environment the transaction was recorded against.
          example: test
        livemode:
          type: boolean
          description: Convenience flag — `true` when `mode` is `live`.
          example: false
        status:
          type: string
          enum:
            - broadcasted
            - pending
            - confirming
            - completed
            - failed
            - refunded
            - partially_refunded
          example: completed
        txHash:
          type: string
          minLength: 64
          maxLength: 128
          example: '0xabcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789'
        walletAddress:
          type: string
          minLength: 32
          maxLength: 128
          example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
          description: The buyer's wallet address.
        merchantWalletAddress:
          type: string
          minLength: 32
          maxLength: 128
          example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
          description: The merchant's payout-configured wallet address for this chain.
        merchantId:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          example: 550e8400-e29b-41d4-a716-446655440000
          description: Tenant key (`merchants.id`).
        paymentLinkId:
          anyOf:
            - type: string
              format: uuid
              pattern: >-
                ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
              example: 550e8400-e29b-41d4-a716-446655440000
            - type: 'null'
          description: Associated payment link, if the transaction was paid via one.
        sessionId:
          anyOf:
            - type: string
              format: uuid
              pattern: >-
                ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
              example: 550e8400-e29b-41d4-a716-446655440000
            - type: 'null'
        customerEmail:
          example: buyer@example.com
          type: string
        customerName:
          example: Jane Buyer
          type: string
        customerAddress:
          example: 123 Market St, San Francisco, CA
          type: string
        customerCountry:
          example: US
          anyOf:
            - type: string
              minLength: 2
              maxLength: 2
            - type: 'null'
        customerState:
          anyOf:
            - type: string
            - type: 'null'
        customerType:
          type: string
        customerBusinessName:
          anyOf:
            - type: string
            - type: 'null'
        customerTaxId:
          anyOf:
            - type: string
            - type: 'null'
        customerTaxIdType:
          anyOf:
            - type: string
            - type: 'null'
        taxIdVerificationId:
          anyOf:
            - type: string
              format: uuid
              pattern: >-
                ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
              example: 550e8400-e29b-41d4-a716-446655440000
            - type: 'null'
        taxExempt:
          type: boolean
        taxExemptionReason:
          anyOf:
            - type: string
            - type: 'null'
        subtotalAmount:
          anyOf:
            - type: number
              description: >-
                USD price as a JSON number. Product and payment-link prices
                support up to 4 decimal places in storage.
              example: 19.9999
            - type: 'null'
        taxAmount:
          anyOf:
            - type: number
              description: >-
                Decimal money amount as a JSON number (USD). Responses coerce DB
                `numeric` values to numbers; very large or high-precision values
                may lose IEEE-754 fidelity.
              example: 19.99
            - type: 'null'
        attempt:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        blockNumber:
          anyOf:
            - type: number
            - type: 'null'
        chainId:
          anyOf:
            - type: number
            - type: 'null'
        tokenAddress:
          anyOf:
            - type: string
            - type: 'null'
        logIndex:
          anyOf:
            - type: number
            - type: 'null'
        collectionWalletAddress:
          anyOf:
            - type: string
            - type: 'null'
        idempotencyKey:
          anyOf:
            - type: string
            - type: 'null'
        errorCode:
          anyOf:
            - type: string
            - type: 'null'
        errorMessage:
          anyOf:
            - type: string
            - type: 'null'
        riskStatus:
          type: string
          enum:
            - pending_review
            - cleared
            - quarantined
            - blocked
        riskReviewedAt:
          anyOf:
            - type: string
              description: >-
                Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
                some routes return Postgres timestamptz (`2026-04-16
                12:34:56.000+00`).
              example: '2026-04-16T12:34:56.000Z'
            - type: 'null'
        riskReviewNotes:
          anyOf:
            - type: string
            - type: 'null'
        sweepStatus:
          type: string
          enum:
            - not_required
            - pending
            - completed
            - failed
            - quarantined
        sweepTxHash:
          anyOf:
            - type: string
            - type: 'null'
        sweptAt:
          anyOf:
            - type: string
              description: >-
                Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
                some routes return Postgres timestamptz (`2026-04-16
                12:34:56.000+00`).
              example: '2026-04-16T12:34:56.000Z'
            - type: 'null'
        customFieldValues:
          type: object
          propertyNames:
            type: string
          additionalProperties: {}
        customFieldDefinitions:
          type: array
          items:
            type: object
            properties:
              key:
                type: string
              label:
                type: string
              type:
                type: string
                enum:
                  - text
                  - email
                  - textarea
                  - select
                  - checkbox
              required:
                type: boolean
              placeholder:
                type: string
              helpText:
                type: string
              maxLength:
                type: integer
                minimum: -9007199254740991
                maximum: 9007199254740991
              options:
                type: array
                items:
                  type: object
                  properties:
                    value:
                      type: string
                    label:
                      type: string
                  required:
                    - value
                    - label
                  additionalProperties: false
            required:
              - key
              - label
              - type
            additionalProperties: false
        clientMetadata:
          description: >-
            Optional client/agent identity captured at payment time (e.g.
            userAgent, agentId).
          anyOf:
            - type: object
              propertyNames:
                type: string
              additionalProperties: {}
            - type: 'null'
        numeralCalculationId:
          anyOf:
            - type: string
            - type: 'null'
        numeralTransactionId:
          anyOf:
            - type: string
            - type: 'null'
        productName:
          description: Payment-link name when `paymentLinkId` is set.
          type: string
        confirmedAt:
          anyOf:
            - type: string
              description: >-
                Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
                some routes return Postgres timestamptz (`2026-04-16
                12:34:56.000+00`).
              example: '2026-04-16T12:34:56.000Z'
            - type: 'null'
        finalizedAt:
          anyOf:
            - type: string
              description: >-
                Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
                some routes return Postgres timestamptz (`2026-04-16
                12:34:56.000+00`).
              example: '2026-04-16T12:34:56.000Z'
            - type: 'null'
        settledAt:
          anyOf:
            - type: string
              description: >-
                Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
                some routes return Postgres timestamptz (`2026-04-16
                12:34:56.000+00`).
              example: '2026-04-16T12:34:56.000Z'
            - type: 'null'
        createdAt:
          type: string
          description: >-
            Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
            some routes return Postgres timestamptz (`2026-04-16
            12:34:56.000+00`).
          example: '2026-04-16T12:34:56.000Z'
        updatedAt:
          type: string
          description: >-
            Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
            some routes return Postgres timestamptz (`2026-04-16
            12:34:56.000+00`).
          example: '2026-04-16T12:34:56.000Z'
      required:
        - id
        - amount
        - amountBaseUnits
        - token
        - network
        - mode
        - livemode
        - status
        - txHash
        - walletAddress
        - merchantWalletAddress
        - merchantId
        - paymentLinkId
        - createdAt
        - updatedAt
      additionalProperties: false
    ApiError:
      type: object
      properties:
        status:
          type: string
          const: error
        code:
          type: string
          enum:
            - BAD_REQUEST
            - VALIDATION_FAILED
            - UNAUTHORIZED
            - FORBIDDEN
            - NOT_FOUND
            - CONFLICT
            - RATE_LIMITED
            - UNPROCESSABLE_ENTITY
            - INTERNAL_ERROR
            - SERVICE_UNAVAILABLE
            - TIMEOUT
            - UPSTREAM_ERROR
            - AUTH_MISSING_CREDENTIALS
            - AUTH_INVALID_API_KEY
            - AUTH_EXPIRED_API_KEY
            - AUTH_INVALID_JWT
            - AUTH_EXPIRED_JWT
            - AUTH_TENANT_MISMATCH
            - AUTH_MERCHANT_NOT_FOUND
            - AUTH_KEY_TYPE_NOT_ALLOWED
            - API_KEY_SCOPE_INSUFFICIENT
            - ADMIN_NOT_AUTHORIZED
            - ADMIN_READONLY
            - TRANSACTION_DUPLICATE
            - TRANSACTION_NOT_FOUND
            - TRANSACTION_INVALID_STATUS
            - TRANSACTION_CHAIN_VERIFY_FAILED
            - PAYMENT_LINK_NOT_FOUND
            - PAYMENT_LINK_INACTIVE
            - PAYMENT_LINK_OWNERSHIP
            - PAYMENT_LINK_EXPIRED
            - PRODUCT_NOT_FOUND
            - PRODUCT_OWNERSHIP
            - PRODUCT_INVALID_PRICE
            - SUBSCRIPTION_NOT_FOUND
            - SUBSCRIPTION_ALREADY_CANCELED
            - SUBSCRIPTION_INVALID_STATUS
            - SUBSCRIPTION_REAUTH_REQUIRED
            - SUBSCRIPTION_BILLING_FAILED
            - SETTLEMENT_NOT_FOUND
            - SETTLEMENT_INSUFFICIENT_BALANCE
            - SETTLEMENT_TRANSFER_FAILED
            - SETTLEMENT_UNSUPPORTED_NETWORK
            - PAYOUT_NOT_CONFIGURED
            - LEDGER_BALANCE_CONFLICT
            - TREASURY_ADDRESS_MISMATCH
            - TREASURY_INSUFFICIENT_BALANCE
            - MANUAL_RECONCILIATION_REQUIRED
            - DISCOUNT_NOT_FOUND
            - DISCOUNT_INACTIVE
            - DISCOUNT_EXPIRED
            - DISCOUNT_MAX_REDEMPTIONS
            - REFUND_NOT_FOUND
            - REFUND_ALREADY_PROCESSED
            - REFUND_EXCEEDS_ORIGINAL
            - REFUND_INSUFFICIENT_MERCHANT_BALANCE
            - REFUND_PAYER_UNKNOWN
            - CUSTOMER_EXISTS
            - CUSTOMER_NOT_FOUND
            - KYB_NOT_FOUND
            - KYB_ALREADY_SUBMITTED
            - ONBOARDING_INCOMPLETE
            - MERCHANT_ACCOUNT_BLOCKED
            - WEBHOOK_SIGNATURE_INVALID
            - WEBHOOK_ENDPOINT_NOT_FOUND
            - WEBHOOK_DELIVERY_FAILED
            - CDP_UPSTREAM_ERROR
            - CHAIN_RPC_ERROR
            - IDEMPOTENCY_KEY_INVALID
            - IDEMPOTENCY_CONFLICT
            - IDEMPOTENCY_IN_PROGRESS
            - IDEMPOTENCY_REPLAY_REDACTED
            - INVITE_INVALID
            - INVITE_EXPIRED
            - INSUFFICIENT_BALANCE
            - URL_BLOCKED
            - CAP_EXCEEDED
            - WALLET_SUSPENDED
            - WALLET_FETCH_DISABLED
            - INVITE_NOT_VOIDABLE
            - ORIGIN_BLOCKED
            - APPROVAL_REQUIRED
            - WITHDRAWAL_NOT_ALLOWED
            - DEPOSIT_NOT_FOUND
            - DEPOSIT_ADDRESS_UNAVAILABLE
            - INSUFFICIENT_CASH_BALANCE
            - SOCIAL_IDENTITY_REUSED
            - SOCIAL_BONUS_NO_IDENTITY
            - SOCIAL_BONUS_SCORE_TOO_LOW
            - SOCIAL_BONUS_UNAVAILABLE
            - PROMO_CREDIT_CEILING
            - PROTOCOL_UNSUPPORTED
            - MPP_UNAVAILABLE
            - SESSION_NOT_FOUND
            - WALLET_TREASURY_NOT_CONFIGURED
            - NETWORK_NOT_ALLOWED
            - PRE_PAYMENT_FAILED
          description: >-
            Canonical BAGS error code. Clients should switch on `code`, not
            `message`. See the error catalog for the full list.
        message:
          type: string
          description: >-
            Human-readable description. May change across versions; do not
            pattern-match.
        details:
          description: Optional, error-specific context.
          type: object
          propertyNames:
            type: string
          additionalProperties: {}
        hint:
          description: >-
            Optional human-oriented remediation hint (e.g. how to supply an API
            key). Do not branch on this field programmatically.
          type: string
        retryAfter:
          description: >-
            Seconds until the caller may retry. Present on some 429 responses;
            `Retry-After` is also set as an HTTP header.
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
      required:
        - status
        - code
        - message
      additionalProperties: false
    PaymentLink:
      type: object
      properties:
        id:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          example: 550e8400-e29b-41d4-a716-446655440000
        productId:
          anyOf:
            - type: string
              format: uuid
              pattern: >-
                ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
              example: 550e8400-e29b-41d4-a716-446655440000
            - type: 'null'
        name:
          type: string
          example: Pro Plan
        description:
          anyOf:
            - type: string
            - type: 'null'
          example: Monthly access to premium features
        amount:
          type: number
          description: >-
            USD price as a JSON number. Product and payment-link prices support
            up to 4 decimal places in storage.
          example: 19.9999
        currency:
          type: string
          const: USD
        network:
          type: string
          enum:
            - solana
            - solana_devnet
            - base
            - base_sepolia
            - ethereum
            - eth_sepolia
            - polygon
            - polygon_amoy
            - arc_testnet
          example: base
          description: >-
            Primary network. Legacy field — prefer `networks` for new
            integrations.
        networks:
          type: array
          items:
            type: string
            enum:
              - solana
              - solana_devnet
              - base
              - base_sepolia
              - ethereum
              - eth_sepolia
              - polygon
              - polygon_amoy
              - arc_testnet
            example: base
          description: All networks this payment link accepts.
        token:
          type: string
          enum:
            - USDC
            - USDT
            - SOL
            - ETH
            - MATIC
            - POL
          example: USDC
        active:
          type: boolean
          example: true
        mode:
          type: string
          enum:
            - live
            - test
          example: live
        livemode:
          type: boolean
          description: Convenience flag — `true` when `mode` is `live`.
          example: true
        pricingType:
          default: one_time
          example: one_time
          type: string
          enum:
            - one_time
            - recurring
        billingInterval:
          anyOf:
            - type: string
              enum:
                - minute
                - week
                - month
                - year
              example: month
            - type: 'null'
        billingIntervalCount:
          anyOf:
            - type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
            - type: 'null'
          example: 1
        trialDays:
          anyOf:
            - type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
            - type: 'null'
          example: 14
        merchantWalletAddress:
          type: string
          minLength: 32
          maxLength: 128
          example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
        merchantId:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          example: 550e8400-e29b-41d4-a716-446655440000
        merchantWalletAddresses:
          type: object
          propertyNames:
            type: string
          additionalProperties:
            type: string
            minLength: 32
            maxLength: 128
            example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
          description: >-
            Network → merchant wallet map for multi-chain acceptance. The
            `merchantWalletAddress` top-level field covers the primary
            `network`.
        merchantName:
          anyOf:
            - type: string
            - type: 'null'
          example: Acme Corp
        merchantLogo:
          description: Merchant logo URL when configured.
          type: string
          format: uri
        totalCollected:
          description: Lifetime collected via this link.
          type: number
          example: 19.9999
        totalTransactions:
          description: Lifetime successful transaction count.
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        customFields:
          type: array
          items:
            type: object
            properties:
              key:
                type: string
              label:
                type: string
              type:
                type: string
                enum:
                  - text
                  - email
                  - textarea
                  - select
                  - checkbox
              required:
                type: boolean
              placeholder:
                type: string
              helpText:
                type: string
              maxLength:
                type: integer
                minimum: -9007199254740991
                maximum: 9007199254740991
              options:
                type: array
                items:
                  type: object
                  properties:
                    value:
                      type: string
                    label:
                      type: string
                  required:
                    - value
                    - label
                  additionalProperties: false
            required:
              - key
              - label
              - type
            additionalProperties: false
        collectionWalletAddresses:
          description: Network → BAGS collection wallet map (payment-link preview).
          type: object
          propertyNames:
            type: string
          additionalProperties:
            type: string
            minLength: 32
            maxLength: 128
            example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
        treasuryWalletAddresses:
          description: Deprecated alias of `collectionWalletAddresses`.
          type: object
          propertyNames:
            type: string
          additionalProperties:
            type: string
            minLength: 32
            maxLength: 128
            example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
        isAgenticProxy:
          type: boolean
          description: >-
            When true, this link is used by an agent as a proxy — the buyer pays
            BAGS, and BAGS forwards to a `targetUrl`.
          example: false
        targetUrl:
          anyOf:
            - type: string
              format: uri
            - type: 'null'
        targetMethod:
          description: >-
            Declared HTTP method agents should use when calling this agentic
            proxy link. NULL defaults to POST. GET/DELETE map inputs to query
            params in Bazaar discovery; POST/PUT/PATCH use a JSON body.
          example: POST
          anyOf:
            - type: string
              enum:
                - GET
                - POST
                - PUT
                - PATCH
                - DELETE
            - type: 'null'
        x402Scheme:
          type: string
          enum:
            - exact
            - upto
          description: >-
            x402 payment scheme for agentic links. 'exact' charges the fixed
            amount; 'upto' authorizes a ceiling and settles actual usage
            (agentic-proxy links only).
          example: exact
        inputSchema:
          description: >-
            Bounded JSON-Schema subset describing request parameters the
            upstream API expects (agentic-proxy links only). Shape: `{
            properties, required? }`.
          example:
            properties:
              url:
                type: string
                description: Page URL to scrape
            required:
              - url
          anyOf:
            - type: object
              propertyNames:
                type: string
              additionalProperties: {}
            - type: 'null'
        inputExample:
          description: >-
            Example input object matching `inputSchema` (agentic-proxy links
            only).
          example:
            url: https://example.com
          anyOf:
            - type: object
              propertyNames:
                type: string
              additionalProperties: {}
            - type: 'null'
        successUrl:
          anyOf:
            - type: string
            - type: 'null'
          example: https://example.com/success
        returnUrl:
          anyOf:
            - type: string
              format: uri
            - type: 'null'
          example: https://example.com/return
        cancelUrl:
          anyOf:
            - type: string
              format: uri
            - type: 'null'
          example: https://example.com/cancel
        createdAt:
          type: string
          description: >-
            Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
            some routes return Postgres timestamptz (`2026-04-16
            12:34:56.000+00`).
          example: '2026-04-16T12:34:56.000Z'
        updatedAt:
          type: string
          description: >-
            Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
            some routes return Postgres timestamptz (`2026-04-16
            12:34:56.000+00`).
          example: '2026-04-16T12:34:56.000Z'
      required:
        - id
        - productId
        - name
        - description
        - amount
        - currency
        - network
        - networks
        - token
        - active
        - mode
        - livemode
        - pricingType
        - billingInterval
        - billingIntervalCount
        - trialDays
        - merchantWalletAddress
        - merchantId
        - merchantWalletAddresses
        - merchantName
        - customFields
        - isAgenticProxy
        - targetUrl
        - x402Scheme
        - successUrl
        - returnUrl
        - cancelUrl
        - createdAt
        - updatedAt
      additionalProperties: false
    Product:
      type: object
      properties:
        id:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          example: 550e8400-e29b-41d4-a716-446655440000
        name:
          type: string
          example: Pro Plan
        description:
          anyOf:
            - type: string
            - type: 'null'
          example: Monthly access to premium features
        amount:
          type: number
          description: >-
            USD price as a JSON number. Product and payment-link prices support
            up to 4 decimal places in storage.
          example: 19.9999
        currency:
          type: string
          const: USD
        active:
          type: boolean
          example: true
        archived:
          type: boolean
          example: false
        mode:
          type: string
          enum:
            - live
            - test
          example: live
        pricingType:
          default: one_time
          example: one_time
          type: string
          enum:
            - one_time
            - recurring
        billingInterval:
          anyOf:
            - type: string
              enum:
                - minute
                - week
                - month
                - year
              example: month
            - type: 'null'
        billingIntervalCount:
          anyOf:
            - type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
            - type: 'null'
          example: 1
        trialDays:
          anyOf:
            - type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
            - type: 'null'
          example: 14
        token:
          type: string
          enum:
            - USDC
            - USDT
            - SOL
            - ETH
            - MATIC
            - POL
          example: USDC
        merchantWalletAddress:
          type: string
          minLength: 32
          maxLength: 128
          example: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0'
        merchantId:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
          example: 550e8400-e29b-41d4-a716-446655440000
        metadata:
          anyOf:
            - type: object
              propertyNames:
                type: string
              additionalProperties: {}
            - type: 'null'
        totalCollected:
          type: number
          description: >-
            USD price as a JSON number. Product and payment-link prices support
            up to 4 decimal places in storage.
          example: 19.9999
        totalTransactions:
          type: integer
          minimum: -9007199254740991
          maximum: 9007199254740991
        createdAt:
          type: string
          description: >-
            Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
            some routes return Postgres timestamptz (`2026-04-16
            12:34:56.000+00`).
          example: '2026-04-16T12:34:56.000Z'
        updatedAt:
          type: string
          description: >-
            Timestamp string. Usually ISO 8601 (`2026-04-16T12:34:56.000Z`);
            some routes return Postgres timestamptz (`2026-04-16
            12:34:56.000+00`).
          example: '2026-04-16T12:34:56.000Z'
      required:
        - id
        - name
        - description
        - amount
        - currency
        - active
        - archived
        - mode
        - pricingType
        - billingInterval
        - billingIntervalCount
        - trialDays
        - token
        - merchantWalletAddress
        - merchantId
        - metadata
        - totalCollected
        - totalTransactions
        - createdAt
        - updatedAt
      additionalProperties: false
    X402ApiV1Index:
      type: object
      properties:
        name:
          type: string
          const: BAGS Agent API
        version:
          type: string
          const: v1
        openapi:
          type: string
          format: uri
        documentation:
          type: string
          format: uri
        api_catalog:
          type: string
          format: uri
        mcp_server:
          type: string
          format: uri
        auth:
          type: string
          format: uri
        x402:
          type: object
          properties:
            protocol:
              type: string
              format: uri
            discovery_challenge:
              type: string
              format: uri
            agentic_payments:
              type: string
              format: uri
            resource_pattern:
              type: string
              format: uri
          required:
            - protocol
            - discovery_challenge
            - agentic_payments
            - resource_pattern
          additionalProperties: false
      required:
        - name
        - version
        - openapi
        - documentation
        - api_catalog
        - mcp_server
        - auth
        - x402
      additionalProperties: false
    X402AgentProxyResponse:
      type: object
      properties:
        ok:
          type: boolean
      additionalProperties: {}
    X402AgentPrice:
      type: object
      properties:
        status:
          type: string
          const: ok
        paymentLinkId:
          type: string
          format: uuid
          pattern: >-
            ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
        resource:
          type: string
          format: uri
        name:
          type: string
        description:
          type: string
        scheme:
          type: string
          enum:
            - exact
            - upto
        network:
          type: string
        caip2Network:
          type: string
        asset:
          type: string
          const: USDC
        mode:
          type: string
          enum:
            - live
            - test
        price:
          type: string
          example: $10.00
        quote:
          type: object
          properties:
            subtotalCents:
              type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
            taxCents:
              type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
              description: Always 0 — flat per-call pricing.
            totalCents:
              type: integer
              minimum: -9007199254740991
              maximum: 9007199254740991
          required:
            - subtotalCents
            - taxCents
            - totalCents
          additionalProperties: false
        optionalCustomerHeaders:
          type: array
          items:
            type: string
      required:
        - status
        - paymentLinkId
        - resource
        - name
        - description
        - scheme
        - network
        - caip2Network
        - asset
        - mode
        - price
        - quote
        - optionalCustomerHeaders
      additionalProperties: false
    X402PaymentReceipt:
      type: object
      properties:
        status:
          type: string
          const: ok
        receipt:
          type: object
          properties:
            type:
              type: string
              const: payment_receipt
            correlationId:
              type: string
              format: uuid
              pattern: >-
                ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
              description: >-
                BAGS transaction id — stable correlation id across confirming →
                completed.
            txHash:
              type: string
            status:
              type: string
              example: completed
            network:
              type: string
            caip2Network:
              anyOf:
                - type: string
                - type: 'null'
            token:
              type: string
            amount:
              type: string
              example: '10.00'
            payer:
              type: string
            paymentLinkId:
              anyOf:
                - type: string
                  format: uuid
                  pattern: >-
                    ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
                - type: 'null'
            resource:
              anyOf:
                - type: string
                  format: uri
                - type: 'null'
            mode:
              type: string
              enum:
                - live
                - test
            createdAt:
              anyOf:
                - type: string
                - type: 'null'
            settledAt:
              anyOf:
                - type: string
                - type: 'null'
          required:
            - type
            - correlationId
            - txHash
            - status
            - network
            - caip2Network
            - token
            - amount
            - payer
            - paymentLinkId
            - resource
            - mode
            - createdAt
            - settledAt
          additionalProperties: false
      required:
        - status
        - receipt
      additionalProperties: false
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: bag_live_… or bag_test_…
      description: >-
        BAGS Agent API key from the dashboard. Standalone agentic keys manage
        products, payment links, and transaction reads.
    sessionCookie:
      type: apiKey
      in: cookie
      name: sb-access-token
      description: >-
        Supabase session token. Used by the first-party dashboard UI; not
        intended for third-party clients.

