FLINT Network Agent Passport API

Issue, resolve, and update Agent Passports: hybrid-signed agent identity credentials with a separate mutable mandate.

GitHub OpenAPI

Operations 4

POST /api/passport Issue an Agent Passport #
GET /api/passport/{passport_id} Resolve a public Agent Passport #
POST /api/passport/{passport_id} Update a mandate, manage a claim, or authorize a Shopify purchase #
POST /api/account/claim Attach an anonymously minted passport to the caller's account #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/flint-network:flint-network-agent-passport-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

flint-network-agent-passport-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: FLINT Agent Transaction Control Agent Passport API
  version: 1.0.0
  description: FLINT verifies agent authority before autonomous economic activity, issues signed verification records, accepts outcome feedback, and returns partner-safe Trust Graph reputation.
  x-guidance: 'Use POST /api/x402/scan for a $0.01 x402-paid bounded pre-transaction scan of a separate intended commerce transaction. Use POST /api/x402/verify for high-assurance $0.01 x402-paid agent-authority verification after obtaining the required FLINT capability and DPoP proof. Free operations are explicitly marked with security: [].'
  contact:
    name: FLINT Support
    email: support@flint.network
    url: https://flint.network
  license:
    name: Proprietary
    identifier: LicenseRef-FLINT-Proprietary
servers:
- url: https://flint.network
  description: Production
security: []
tags:
- name: Agent Passport
  description: 'Issue, resolve, and update Agent Passports: hybrid-signed agent identity credentials with a separate mutable mandate.'
paths:
  /api/passport:
    post:
      x-flint-release-state: production
      security: []
      tags:
      - Agent Passport
      operationId: issueAgentPassport
      summary: Issue an Agent Passport
      description: Issues a hybrid-signed (ES256 + ML-DSA-65) Agent Passport that binds an agent to its controller and wallet. The passport signs identity only; the mandate is a separate, unsigned, mutable config. Persists the passport, seeds the Trust Graph, and returns a public resolvable id. Free and per-IP rate limited.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PassportIssueRequest'
      responses:
        '200':
          description: Passport issued.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PassportResponse'
        '400':
          description: Invalid request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limited.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /api/passport/{passport_id}:
    get:
      x-flint-release-state: production
      security: []
      tags:
      - Agent Passport
      operationId: resolveAgentPassport
      summary: Resolve a public Agent Passport
      description: Returns the signed passport envelope, decoded identity, current mandate, and a verification summary (signature valid, status, not expired).
      parameters:
      - name: passport_id
        in: path
        required: true
        schema:
          type: string
          pattern: ^kya_
        description: Passport id (kya_ prefix + ULID).
      responses:
        '200':
          description: Passport resolved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PassportResponse'
        '404':
          description: Passport not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    post:
      x-flint-release-state: production
      security:
      - {}
      - WorkOSOwnerSession: []
      tags:
      - Agent Passport
      operationId: updateAgentMandate
      summary: Update a mandate, manage a claim, or authorize a Shopify purchase
      description: 'Dispatches on the request body''s action field (default update_mandate when omitted): update_mandate (mutable mandate config), begin_claim (validate a claim token and open a pending claim), refresh_claim_token (rotate a lost or consumed claim token), issue_purchase_authorization, or issue_preflight_capability. Updating the mandate is a pure data update: it bumps the mandate version and signs nothing, so the passport signature is unchanged.'
      parameters:
      - name: passport_id
        in: path
        required: true
        schema:
          type: string
          pattern: ^kya_
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
              - $ref: '#/components/schemas/MandateUpdateRequest'
              - $ref: '#/components/schemas/BeginClaimRequest'
              - $ref: '#/components/schemas/RefreshClaimTokenRequest'
              - $ref: '#/components/schemas/PurchaseAuthorizationRequest'
      responses:
        '200':
          description: Mandate updated (signature unchanged), or a claim step (begin_claim / refresh_claim_token) completed.
          content:
            application/json:
              schema:
                oneOf:
                - $ref: '#/components/schemas/MandateUpdateResponse'
                - $ref: '#/components/schemas/BeginClaimResponse'
                - $ref: '#/components/schemas/RefreshClaimTokenResponse'
        '201':
          description: Purchase authorization issued.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PurchaseAuthorizationResponse'
        '400':
          description: Invalid request, such as a missing claim_token on begin_claim.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: claim_token_invalid (begin_claim with a wrong or expired token), refresh_not_authorized (refresh_claim_token with neither a valid management_token nor an authorized session), or the mandate-update owner/claim-token checks.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: passport_not_found, or no_pending_claim (begin_claim / refresh_claim_token with no open claim to act on).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: passport_already_owned (begin_claim / refresh_claim_token on a passport that is already claimed), passport_revoked, or passport_frozen.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '410':
          description: 'passport_superseded: this passport was replaced by a remint while it was still unclaimed. superseded_by names the replacement.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Too many refresh_claim_token requests.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /api/account/claim:
    post:
      x-flint-release-state: staging
      security:
      - WorkOSOwnerSession: []
      - bearerAgentSession: []
      tags:
      - Agent Passport
      operationId: claimPassportOwnership
      summary: Attach an anonymously minted passport to the caller's account
      description: 'Attaches an unclaimed passport to the authenticated caller''s FLINT account. Two request shapes: { passport_id, claim_token } presents the one-time token from the mint''s claim_url. { passport_id } alone works only when the caller''s account already holds a pending-claim binding for this passport (begin_claim or refresh_claim_token while signed in, the MCP claim flow, or the flint_claim_intent cookie surviving an OTP delay). Every non-owned failure returns a distinct reason code instead of one shared error string.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
              - $ref: '#/components/schemas/ClaimByTokenRequest'
              - $ref: '#/components/schemas/ClaimBySessionRequest'
      responses:
        '200':
          description: Passport claimed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClaimResponse'
        '400':
          description: Invalid request body or passport_id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: No WorkOSOwnerSession cookie or bearerAgentSession token was presented.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: 'claim_token_invalid: the claim token is wrong.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClaimErrorResponse'
        '404':
          description: 'no_pending_claim: this passport has no open claim to redeem.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClaimErrorResponse'
        '409':
          description: 'passport_already_owned: this passport is already claimed.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClaimErrorResponse'
        '410':
          description: 'passport_superseded: this passport was replaced by a remint while unclaimed.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClaimErrorResponse'
        '429':
          description: Too many claim attempts.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    RefreshClaimTokenResponse:
      type: object
      properties:
        ok:
          type: boolean
        passport_id:
          type: string
        claim_url:
          type: string
          description: New one-time claim link. The old link stops working.
        claim_token:
          type: string
          description: New raw claim token, equal to management_token.
        management_token:
          type: string
        claim_state:
          type: string
          enum:
          - pending
        refreshed_at:
          type: string
          format: date-time
    Ownership:
      type: object
      description: Public-safe ownership and claim lifecycle state for a passport. Never includes emails or raw WorkOS user ids. Identical shape on the issue response, GET /api/passport/{passport_id}, and POST /api/account/claim.
      properties:
        owned:
          type: boolean
          description: True once a FLINT account holds this passport.
        unclaimed:
          type: boolean
          description: The logical negation of owned.
        claimed_at:
          type:
          - string
          - 'null'
          format: date-time
          description: When the passport was claimed. Null while unclaimed.
        owner_account_ref:
          type:
          - string
          - 'null'
          description: 'One-way account reference: "acct_" followed by the first 16 hex characters of sha256(owner user id). Never the raw WorkOS user id or email. Null while unclaimed.'
        claim_state:
          type: string
          enum:
          - claimed
          - pending
          - superseded
          - none
          description: '"claimed": owned. "pending": unclaimed with an open claim token. "superseded": unclaimed and replaced by a remint. "none": unclaimed with no open claim (claim-token storage failed at mint, or it was consumed with no refresh).'
        superseded_by:
          type:
          - string
          - 'null'
          description: passport_id of the passport that superseded this one, when this passport was UNCLAIMED at the time of a remint with the same controller_id and agent_id. Null otherwise. A CLAIMED passport is never superseded automatically.
        supersedes:
          type: array
          items:
            type: string
          description: passport_id values this passport superseded at mint (prior unclaimed passports for the same controller_id and agent_id).
        protection_state:
          type: string
          enum:
          - unprotected
          - armed_no_channel
          - protected
          - frozen
          - revoked
          description: 'Sentinel protection summary: unprotected (not claimed or not armed), armed_no_channel (armed, no alert channel linked), protected (armed with a channel), frozen, or revoked.'
    PassportResponse:
      type: object
      properties:
        passport_id:
          type: string
          description: kya_ prefix + ULID.
        flint_agent_id:
          type: string
          description: Trust Graph node key (faid_ prefix).
        passport:
          type: object
          description: Hybrid-v0 signature envelope.
          properties:
            envelope_version:
              type: string
              example: hybrid-v0
            jws:
              type: string
              description: ES256 compact JWS over the identity-only payload.
            pq_signature:
              type:
              - string
              - 'null'
              description: ML-DSA-65 signature (base64url).
            pq_kid:
              type:
              - string
              - 'null'
            pq_alg:
              type:
              - string
              - 'null'
        mandate:
          $ref: '#/components/schemas/Mandate'
        verification:
          type: object
          properties:
            signature_valid:
              type: boolean
            status:
              type: string
            not_expired:
              type: boolean
            valid:
              type: boolean
        identity:
          $ref: '#/components/schemas/PassportIdentity'
        mint_src:
          type: string
          description: Sanitized mint source label.
        owned:
          type: boolean
          description: Top-level mirror of ownership.owned, for cheap assertions.
        unclaimed:
          type: boolean
          description: Top-level mirror of ownership.unclaimed.
        claim_state:
          type: string
          enum:
          - claimed
          - pending
          - superseded
          - none
          description: Top-level mirror of ownership.claim_state.
        superseded_by:
          type:
          - string
          - 'null'
          description: Top-level mirror of ownership.superseded_by.
        ownership:
          $ref: '#/components/schemas/Ownership'
        claim_url:
          type: string
          description: One-time claim link. Present only on an anonymous (unowned) mint whose claim token was stored successfully. Absent on an owned mint.
        existing_claimed_passports:
          type: array
          items:
            type: string
          description: passport_id values for prior CLAIMED passports with the same controller_id and agent_id that a remint left alone (never superseded automatically). Present only when at least one exists.
        warnings:
          type: array
          items:
            type: string
          description: Response-level warnings, such as an existing_claimed_passports notice.
        mandate_warnings:
          type: array
          items:
            type: string
          description: Copy of mandate.mandate_warnings, surfaced at the top level for convenience.
    ClaimResponse:
      type: object
      properties:
        ok:
          type: boolean
        owned:
          type: boolean
          enum:
          - true
        passport_id:
          type: string
        passport_url:
          type: string
        ownership:
          $ref: '#/components/schemas/Ownership'
    MandateUpdateRequest:
      type: object
      properties:
        action:
          type: string
          enum:
          - update_mandate
        allowed_actions:
          type: array
          items:
            type: string
        max_transaction_amount:
          type: number
        notes:
          type: string
        management_token:
          type: string
          pattern: ^[A-Za-z0-9_-]{32,128}$
          description: 'Required to update the mandate of an UNCLAIMED passport: the raw claim token, presented as a management capability. Not needed once the passport is claimed; the owner''s session (WorkOSOwnerSession cookie or bearerAgentSession) is used instead.'
    PassportIdentity:
      type: object
      description: 'The identity-only payload that is hybrid-signed into the passport envelope. record_version stays "1.0": controller_name and controller_assurance are additive fields, not a version bump.'
      properties:
        passport_id:
          type: string
        record_type:
          type: string
          example: agent_passport
        record_version:
          type: string
          example: '1.0'
        issuer:
          type: string
          example: flint
        issuer_key_id:
          type: string
        status:
          type: string
          example: stamped
        issued_at:
          type: string
          format: date-time
        expires_at:
          type: string
          format: date-time
        agent_id:
          type: string
        agent_name:
          type:
          - string
          - 'null'
        controller_id:
          type: string
          description: Who is accountable on the signed identity. Not the same as the FLINT account that owns the passport (see Ownership.owner_account_ref).
        controller_type:
          type: string
          enum:
          - user
          - organization
        controller_name:
          type:
          - string
          - 'null'
          maxLength: 120
          description: Optional human-readable display label for the controller. Null when not supplied.
        controller_assurance:
          type: string
          enum:
          - verified
          - unverified
          - command
          description: '"command" when FLINT Command set the controller. "verified" when the minting session''s account email equals controller_id (case-insensitive), or an authenticated session''s org is the controller. "unverified" otherwise, including every anonymous mint.'
        wallet_address:
          type: string
        attestations:
          type: array
          items:
            type: object
        core_record_hash:
          type: string
    RefreshClaimTokenRequest:
      type: object
      required:
      - action
      properties:
        action:
          type: string
          enum:
          - refresh_claim_token
        management_token:
          type: string
          description: The current raw claim token, even one about to be superseded. Optional when the caller's session (WorkOSOwnerSession cookie or bearerAgentSession) already began this passport's claim, or minted it.
    PurchaseAuthorizationEnvelope:
      type: object
      required:
      - envelope_version
      - jws
      properties:
        envelope_version:
          type: string
          example: hybrid-v0
        jws:
          type: string
          description: ES256 compact JWS over the purchase authorization.
        pq_signature:
          type:
          - string
          - 'null'
          description: Parallel ML-DSA-65 signature when configured.
        pq_kid:
          type:
          - string
          - 'null'
        pq_alg:
          type:
          - string
          - 'null'
    ClaimBySessionRequest:
      type: object
      required:
      - passport_id
      properties:
        passport_id:
          type: string
          pattern: ^kya_
      description: 'Valid only when the caller''s authenticated account already holds a pending-claim binding for this passport_id: begin_claim while signed in, refresh_claim_token while signed in, the MCP claim flow, or the flint_claim_intent cookie set by begin_claim while signed out (survives an OTP delay and the /welcome new-account redirect within its 30-minute window).'
    PassportIssueRequest:
      type: object
      required:
      - agent
      properties:
        agent:
          type: object
          description: Agent identity. Signed into the passport.
          properties:
            agent_id:
              type: string
            agent_name:
              type: string
            controller_id:
              type: string
            controller_type:
              type: string
              enum:
              - user
              - organization
            wallet_address:
              type: string
            attestations:
              type: array
              items:
                type: object
            controller_name:
              type: string
              maxLength: 120
              description: 'Optional human-readable display label for the controller, signed into the passport identity right after controller_type. Distinct from controller_id: controller_id is the accountable identifier, controller_name is a display label. Null when not supplied.'
        mandate:
          type: object
          description: Mutable spend authority captured at issue. NOT part of the passport signature.
          properties:
            allowed_actions:
              type: array
              items:
                type: string
                enum:
                - commerce_purchase
                - checkout.purchase
                - invoice.pay
                - subscription.renew
                - refund.request
                - quote.retrieve
                - x402_verification_purchase
                - stablecoin_transfer
                - paid_api_access
                - x402_request
                - agent_checkout
                - delegated_spending
                - project.read
                - ALL
                description: 'One FLINT mandate vocabulary action (see api/lib/mandate-actions.js), or the "ALL" preset. "ALL" (case-insensitive) or the legacy alias "all_commerce_v1" expands server-side to the full vocabulary list at mint or update time; the stored mandate keeps the expanded allowed_actions and also records preset: "ALL" so a client can render one checkbox instead of the full list. A string outside this vocabulary is kept for backward compatibility but is reported back in mandate_warnings and will not match any scan until it is added to the vocabulary or aliased.'
            max_transaction_amount:
              type: number
            notes:
              type: string
        supersede_management_token:
          type: string
          description: Optional. The management_token (raw claim token) of a specific prior UNCLAIMED passport with the same agent_id and controller_id. Presenting it authorizes superseding that prior passport at mint even with no authenticated session, since it proves possession of that prior's own claim link. Without it, and without a session whose controller_assurance is verified or command, a remint that reuses a prior's agent_id and controller_id does not supersede that prior; the prior is left alone and reported back in related_passports with a warning instead.
    PurchaseAuthorizationRequest:
      type: object
      required:
      - action
      - shop
      - currency
      - max_amount
      properties:
        action:
          type: string
          enum:
          - issue_purchase_authorization
        shop:
          type: string
          pattern: ^[a-z0-9][a-z0-9-]*\.myshopify\.com$
        currency:
          type: string
          pattern: ^[A-Z]{3}$
        max_amount:
          type: number
          exclusiveMinimum: 0
    BeginClaimResponse:
      type: object
      properties:
        ok:
          type: boolean
        claim_state:
          type: string
          enum:
          - pending
        passport_id:
          type: string
    Mandate:
      type: object
      description: Unsigned, mutable mandate config read at decision time.
      properties:
        passport_id:
          type: string
        allowed_actions:
          type: array
          items:
            type: string
            description: A FLINT mandate vocabulary action. When the mandate was set with the ALL preset this is the full expanded vocabulary list, not the literal string "ALL".
        max_transaction_amount:
          type: number
        notes:
          type:
          - string
          - 'null'
        version:
          type: integer
        updated_at:
          type: string
          format: date-time
        preset:
          type:
          - string
          - 'null'
          enum:
          - ALL
          - null
          description: '"ALL" when allowed_actions was set via the ALL preset (or its legacy alias all_commerce_v1) and was expanded server-side to the full vocabulary. Null when allowed_actions was set explicitly.'
        mandate_warnings:
          type: array
          items:
            type: string
          description: One warning per allowed_actions entry that is not in the FLINT mandate vocabulary and is not the ALL preset. The action is kept (backward compatible) but will not match actionPermitted until it is added to the vocabulary or aliased.
    BeginClaimRequest:
      type: object
      required:
      - action
      - claim_token
      properties:
        action:
          type: string
          enum:
          - begin_claim
        claim_token:
          type: string
          description: The one-time claim token from the mint's claim_url.
    PurchaseAuthorizationResponse:
      type: object
      required:
      - ok
      - authorization
      - purchase_authorization
      properties:
        ok:
          type: boolean
        authorization:
          type: object
          description: Decoded owner authorization claims, including Passport, shop, action, amount, currency, mandate version, and expiry.
        purchase_authorization:
          $ref: '#/components/schemas/PurchaseAuthorizationEnvelope'
        usage:
          type: string
    ClaimErrorResponse:
      type: object
      description: Every non-owned claim failure returns a distinct reason so a caller (UI or MCP agent) can tell them apart, instead of one shared error string.
      properties:
        error:
          type: string
          enum:
          - passport_already_owned
          - passport_superseded
          - claim_token_invalid
          - no_pending_claim
        reason:
          type: string
          enum:
          - owned
          - superseded
          - invalid_token
          - no_pending_claim
        superseded_by:
          type: string
          description: Present only when error is passport_superseded.
        message:
          type: string
          description: Human-readable copy for the UI.
    ErrorResponse:
      type: object
      properties:
        ok:
          type: boolean
        error:
          type: string
        detail:
          type: string
    ClaimByTokenRequest:
      type: object
      required:
      - passport_id
      - claim_token
      properties:
        passport_id:
          type: string
          pattern: ^kya_
        claim_token:
          type: string
          description: The one-time claim token from the mint's claim_url.
    MandateUpdateResponse:
      type: object
      properties:
        ok:
          type: boolean
        passport_id:
          type: string
        mandate:
          $ref: '#/components/schemas/Mandate'
        passport_signature_unchanged:
          type: boolean
          description: 'Always true: a mandate update never re-signs the passport.'
  securitySchemes:
    WorkOSOwnerSession:
      type: apiKey
      in: cookie
      name: flint_session
      description: Sealed WorkOS session required for claimed-Passport owner actions. Unclaimed mandate updates require the claim token as a management capability.
    PartnerServiceBearer:
      type: http
      scheme: bearer
      description: Server-only partner credential. The authenticated partner must match the partner in the stored signed verification record.
    X402Payment:
      type: apiKey
      in: header
      name: PAYMENT-SIGNATURE
      description: Canonical x402 v2 payment proof on a paid retry. Initial unpaid challenge requests require no payment proof.
    FlintCapability:
      type: apiKey
      in: header
      name: FLINT-CAPABILITY
      description: Short-lived Passport-owner-issued capability bound to the exact x402 Verify request.
    DPoP:
      type: apiKey
      in: header
      name: DPoP
      description: Fresh caller proof bound to the capability, request, and x402 payment proof.
    X401Proof:
      type: apiKey
      in: header
      name: PROOF-RESPONSE
      description: Base64url-encoded x401 principal-identity presentation. Omit to request a proof challenge.
    bearerAgentSession:
      type: http
      scheme: bearer
      bearerFormat: flint_sess_...
      description: 'Agent session bearer token minted by POST /api/auth/otp-verify (Authorization: Bearer flint_sess_...). Accepted everywhere a WorkOSOwnerSession cookie is accepted, so an MCP agent never needs a browser. Also accepted via the X-FLINT-Session header.'