{
 "openapi": "3.1.0",
 "info": {
  "title": "AgentDrives API",
  "version": "1.4.0",
  "description": "Everything a person can do on AgentDrives, an agent can do over HTTP, with no browser and no CAPTCHA. An agent with no address of its own signs up in one call (POST /api/agents/signup: an account and a key at once, and a claim link for its person; until a person claims it or it pays for a Drive, 1 free check a day and a Drive it pays over HTTP 402). Or sign in with an emailed 6-digit code, create an API key, claim your product's domain, prove it is yours, order drives, cancel, and delete your account. Order of steps: claim (POST /api/claims; an account email on the domain verifies at once, unless the domain is a mailbox provider's), verify (a code mailed to an address at the domain, a DNS TXT record, a meta tag on the home page or a file), then order. The free check needs no claim (product free: private, it lists nothing); a verified product gets one queued. Every other order without a verified claim fails with 403 claim_not_verified and the fix. Only driven products are in the directory. Errors carry a `fix` field. API keys: 1,000 requests per hour each. When online payment is on, an order returns payment.url to pay at; otherwise payment is null and the order is confirmed by email. A Drive also returns payment.agent: pay it without a person over HTTP 402 at POST /api/orders/{id}/payment, with MPP or x402: a card through a Stripe Shared Payment Token, or USDC on Base or Tempo. The price includes any VAT, and every payment has a receipt. An EU business that sends its VAT ID gets our invoice.",
  "contact": {
   "email": "hello@agentdrives.com"
  },
  "x-guidance": "Find software an AI agent can use on its own: POST /api/paid/find-tools with {\"task\": \"send an invoice\"} answers with ranked products, each with its agent level (0 to 5), whether an agent gets in without a person, and what our agent got done in a real drive. $0.01 a call over x402 or MPP (USDC on Base or Tempo): the first request answers 402 with the challenges. For many calls, buy credit once: POST /api/credits/topup with {\"amount_usd\": 5} returns an API key that holds 500 calls; send it as x-api-key. The same search is free, rate-limited per IP, at GET /api/find-tools?task=…. To have a product of your own driven: POST /api/agents/signup for a key, claim and prove its domain (POST /api/claims), POST /api/orders with product drive, then pay $49 at POST /api/orders/{id}/payment."
 },
 "x-service-info": {
  "categories": [
   "developer-tools",
   "data"
  ],
  "docs": {
   "homepage": "https://agentdrives.com/data",
   "apiReference": "https://agentdrives.com/openapi.json",
   "llms": "https://agentdrives.com/llms.txt"
  }
 },
 "servers": [
  {
   "url": "https://agentdrives.com"
  }
 ],
 "security": [
  {
   "apiKey": []
  },
  {
   "bearer": []
  }
 ],
 "paths": {
  "/api/auth/email-otp/send-verification-otp": {
   "post": {
    "operationId": "sendCode",
    "summary": "Email a 6-digit sign-in code (creates the account on first sign-in)",
    "security": [],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "email": {
          "type": "string",
          "format": "email"
         },
         "type": {
          "const": "sign-in"
         }
        },
        "required": [
         "email",
         "type"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Code sent"
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/auth/sign-in/email-otp": {
   "post": {
    "operationId": "signIn",
    "summary": "Sign in with the code; returns a session token to use as Bearer",
    "security": [],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "email": {
          "type": "string"
         },
         "otp": {
          "type": "string",
          "pattern": "^[0-9]{6}$"
         }
        },
        "required": [
         "email",
         "otp"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Signed in",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "token": {
           "type": "string"
          },
          "user": {
           "$ref": "#/components/schemas/User"
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/auth/api-key/create": {
   "post": {
    "operationId": "createApiKey",
    "summary": "Create an API key (shown once)",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "name": {
          "type": "string"
         }
        },
        "required": []
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "id": {
           "type": "string"
          },
          "key": {
           "type": "string",
           "description": "Send as x-api-key"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/api/auth/api-key/list": {
   "get": {
    "operationId": "listApiKeys",
    "summary": "List API keys (without the secret)",
    "responses": {
     "200": {
      "description": "Keys"
     }
    }
   }
  },
  "/api/auth/api-key/delete": {
   "post": {
    "operationId": "deleteApiKey",
    "summary": "Revoke an API key",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "keyId": {
          "type": "string"
         }
        },
        "required": [
         "keyId"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Revoked"
     }
    }
   }
  },
  "/api/agents/signup": {
   "post": {
    "operationId": "agentSignUp",
    "summary": "An account for an agent, with no person, no address and no CAPTCHA: its API key at once (shown once; send it as x-api-key; 100 requests an hour) and a claim link for its person (valid 7 days). Until a person claims it or it pays for a Drive: 1 free check a day, a Drive paid over HTTP 402 (POST /api/orders/{id}/payment), proving a domain by DNS, meta tag or file; anything else answers 403 claim_required. email (optional): the person's address, the claim link goes there too. At most 5 sign-ups an hour and 20 a day from one address (429)",
    "security": [],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "agent": {
          "type": "string",
          "maxLength": 60,
          "description": "Your name as an agent, e.g. claude-code"
         },
         "email": {
          "type": "string",
          "format": "email",
          "description": "Optional: your person's address, for the claim link"
         }
        },
        "required": []
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "The account, its key, its limits and the claim link",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AgentSignup"
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/agents/claim-link": {
   "post": {
    "operationId": "agentClaimLink",
    "summary": "A new claim link for your own agent account (the old one stops working). At most 5 a day (429)",
    "responses": {
     "200": {
      "description": "The claim link",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "claim": {
           "$ref": "#/components/schemas/ClaimLink"
          }
         }
        }
       }
      }
     },
     "409": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/agents/claim": {
   "post": {
    "operationId": "claimAgentAccount",
    "summary": "A person takes an agent's account over: signed in with their own session (a cookie or the Bearer token of a code sign-in, never an API key), with the token from the claim link (the part after #t=). First with preview: true (which agent made it and what comes with it; nothing moves), then with confirm: true: the agent's orders, claims and follows move into their account, the agent's keys stop working, and one new key is made on their account, shown in their dashboard (/app/keys) to give the agent. Needs an address proved by sign-in (403 email_not_verified); without preview or confirm: 400 confirm_required with the preview; at most 10 tries an hour (429)",
    "security": [
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "token": {
          "type": "string"
         },
         "preview": {
          "type": "boolean",
          "description": "true: nothing moves; the answer says what comes with it (agent, when it was made, keys, orders, claimed domains)"
         },
         "confirm": {
          "type": "boolean",
          "description": "true: take it over"
         }
        },
        "required": [
         "token"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Claimed (or, with preview, what comes with it)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "account": {
           "type": "string"
          },
          "moved": {
           "type": "object"
          },
          "preview": {
           "type": "boolean"
          },
          "agent": {
           "type": [
            "string",
            "null"
           ]
          },
          "made_at": {
           "type": [
            "string",
            "null"
           ],
           "format": "date-time"
          },
          "keys": {
           "oneOf": [
            {
             "type": "integer",
             "description": "preview: the agent's keys, which stop working"
            },
            {
             "type": "object",
             "description": "claimed: how many keys were revoked, and the new key (id, name, start; its value in the dashboard)"
            }
           ]
          },
          "orders": {
           "type": "array",
           "items": {
            "type": "object"
           }
          },
          "claims": {
           "type": "integer"
          },
          "domains": {
           "type": "array",
           "items": {
            "type": "object"
           }
          },
          "after": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "410": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/orders/{id}/payment": {
   "post": {
    "operationId": "payOrder",
    "summary": "Pay a Drive (ordered as product drive) that waits for payment, as an agent, without a person: HTTP 402. Without a credential: 402 with the challenges. Pay one and send the same request again with the credential (Authorization: Payment for MPP, PAYMENT-SIGNATURE for x402): the paid order, its drive queued, and the receipt (Payment-Receipt or PAYMENT-RESPONSE). No key needed: the order's id is enough. An order waits 24 hours for its payment (409 expired); paid already: 409 already_paid; one payment at a time (409 payment_in_progress). On a person's account the card checkout works too (payment.url in the answer to POST /api/orders); an agent's own account has none until a person claims it. The 402's fix and payment.agent.how name only the rails that are on now.",
    "security": [],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "buyer": {
          "type": "object",
          "description": "Optional, a Drive paid over HTTP 402: for our invoice. The price includes any VAT. An EU VAT ID that VIES confirms gets our invoice at once, with no VAT outside the Netherlands. 400 invalid_vat_id, invalid_country or invalid_buyer",
          "properties": {
           "vat_id": {
            "type": "string",
            "description": "EU VAT ID with its country prefix",
            "example": "DE123456789"
           },
           "country": {
            "type": "string",
            "description": "Two-letter code of your business's country",
            "example": "US"
           },
           "company": {
            "type": "string",
            "description": "Business name for the invoice"
           },
           "address": {
            "type": "string",
            "description": "Postal address for the invoice, one line"
           }
          }
         }
        }
       }
      }
     }
    },
    "x-payment-info": {
     "price": {
      "mode": "fixed",
      "currency": "USD",
      "amount": "49.00"
     },
     "protocols": [
      {
       "x402": {}
      },
      {
       "mpp": {
        "method": "evm",
        "intent": "charge",
        "currency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
       }
      },
      {
       "mpp": {
        "method": "tempo",
        "intent": "charge",
        "currency": "0x20C000000000000000000000b9537d11c60E8b50"
       }
      },
      {
       "mpp": {
        "method": "stripe",
        "intent": "charge",
        "currency": "usd"
       }
      }
     ],
     "offers": [
      {
       "method": "stripe",
       "intent": "charge",
       "amount": "4900",
       "currency": "usd",
       "description": "A Drive by card, through a Stripe Shared Payment Token"
      },
      {
       "method": "evm",
       "intent": "charge",
       "amount": "49000000",
       "currency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
       "description": "A Drive in USDC on Base (MPP evm, or x402 exact), when stablecoins are on"
      },
      {
       "method": "tempo",
       "intent": "charge",
       "amount": "49000000",
       "currency": "0x20C000000000000000000000b9537d11c60E8b50",
       "description": "A Drive in USDC on Tempo, when stablecoins are on"
      }
     ]
    },
    "responses": {
     "200": {
      "description": "Paid: the order and the payment",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/AgentPayment"
        }
       }
      }
     },
     "402": {
      "description": "Payment Required: the challenges in WWW-Authenticate (MPP: Payment, method stripe, tempo or evm) and PAYMENT-REQUIRED (x402 v2, exact, USDC on Base), and a body with error payment_required, what it buys, accepts (the rails on now), fix and, in Stripe's test mode, test_mode: true",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentRequired"
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "502": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/orders/{id}/receipt": {
   "get": {
    "operationId": "orderReceipt",
    "summary": "The receipt of a Drive paid over HTTP 402: the price, the VAT inside it and the payment, as a page to keep or print; ?download=1 as a file. No key needed: the order's id is enough. A business whose VAT ID VIES confirmed finds our invoice linked from it",
    "security": [],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "download",
      "in": "query",
      "required": false,
      "schema": {
       "enum": [
        "1"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The receipt",
      "content": {
       "text/html": {
        "schema": {
         "type": "string"
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/paid/find-tools": {
   "post": {
    "operationId": "findToolsForTaskPaid",
    "summary": "GET /api/find-tools's search, paid per call ($0.01 a call), with no rate limit. With x-api-key and prepaid credit (POST /api/credits/topup) it answers at once and takes $0.01 from the balance: credit in the body, X-Balance-Remaining in the headers. Without a key, or with no credit left, it answers 402 with both ways: pay this call (the challenges) or top up (topup, and balance_cents with a key). A key that doesn't work: 401; more than 1,000 calls a minute per key: 429. Paying per call takes stablecoins only (USDC on Base by x402 or MPP evm, or Tempo): a card's minimum is above the price. While paying over HTTP 402 is off it answers 503 not_available; the same search is free at GET /api/find-tools. The arguments are checked before any payment (400)",
    "security": [
     {},
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "task": {
          "type": "string",
          "example": "send an invoice"
         },
         "category": {
          "type": "string"
         },
         "self_signup": {
          "type": "boolean"
         },
         "min_level": {
          "$ref": "#/components/schemas/Level"
         },
         "limit": {
          "type": "integer",
          "minimum": 1,
          "maximum": 25,
          "default": 10
         }
        },
        "required": [
         "task"
        ]
       }
      }
     }
    },
    "x-payment-info": {
     "price": {
      "mode": "fixed",
      "currency": "USD",
      "amount": "0.01"
     },
     "protocols": [
      {
       "x402": {}
      },
      {
       "mpp": {
        "method": "evm",
        "intent": "charge",
        "currency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
       }
      },
      {
       "mpp": {
        "method": "tempo",
        "intent": "charge",
        "currency": "0x20C000000000000000000000b9537d11c60E8b50"
       }
      }
     ],
     "offers": [
      {
       "method": "evm",
       "intent": "charge",
       "amount": "10000",
       "currency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
       "description": "One task search in USDC on Base (MPP evm, or x402 exact)"
      },
      {
       "method": "tempo",
       "intent": "charge",
       "amount": "10000",
       "currency": "0x20C000000000000000000000b9537d11c60E8b50",
       "description": "One task search in USDC on Tempo"
      }
     ]
    },
    "responses": {
     "200": {
      "description": "The ranked products",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "task": {
           "type": "string"
          },
          "results": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/TaskResult"
           }
          },
          "credit": {
           "type": "object",
           "description": "The account's credit after this call",
           "properties": {
            "balance_cents": {
             "type": "integer"
            },
            "calls_left": {
             "type": "integer"
            },
            "expires_at": {
             "type": [
              "string",
              "null"
             ],
             "format": "date-time"
            },
            "paid_cents": {
             "type": "integer",
             "description": "What this call took"
            },
            "low": {
             "type": "boolean",
             "description": "50 calls left or fewer: time to top up"
            },
            "topup": {
             "type": "object",
             "description": "How to top up, when low"
            }
           }
          }
         }
        }
       }
      },
      "headers": {
       "X-Balance-Remaining": {
        "description": "Paid from credit: what's left, in US dollars",
        "schema": {
         "type": "string",
         "example": "4.99"
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "402": {
      "description": "Payment Required: the challenges in WWW-Authenticate (MPP: Payment, method stripe, tempo or evm) and PAYMENT-REQUIRED (x402 v2, exact, USDC on Base), and a body with error payment_required, what it buys, accepts (the rails on now), fix and, in Stripe's test mode, test_mode: true",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentRequired"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/credits/topup": {
   "post": {
    "operationId": "topUpCredit",
    "summary": "Buy prepaid credit for paid calls over HTTP 402: $5 for 500 calls, $20 for 2,000 calls, $50 for 5,000 calls. Without a credential: 402 with the challenges (MPP: a card through a Stripe Shared Payment Token, or USDC on Tempo or Base; x402: USDC on Base). Pay one and send the same request again with the credential. With x-api-key the credit goes onto that key's account; without one the top-up makes an agent account and returns its key (api_key, shown once), which holds the credit, and a claim link for its person. Send an Idempotency-Key header with both requests: the same key answers the same and never pays twice. A balance holds at most $100 (409 balance_full) and lasts 12 months from the last top-up; it pays for paid calls only, not a Drive. A key's top-up while more than 50 calls are left: 409 balance_not_low unless force: true. The price includes any VAT, and every payment has a receipt. An EU business that sends its VAT ID gets our invoice. The answer has the balance and a receipt_url",
    "parameters": [
     {
      "name": "Idempotency-Key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string",
       "minLength": 8,
       "maxLength": 200
      },
      "description": "A UUID of your own, the same on every retry of this top-up"
     }
    ],
    "security": [
     {},
     {
      "apiKey": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "amount_usd": {
          "enum": [
           5,
           20,
           50
          ]
         },
         "buyer": {
          "type": "object",
          "description": "Optional, a Drive paid over HTTP 402: for our invoice. The price includes any VAT. An EU VAT ID that VIES confirms gets our invoice at once, with no VAT outside the Netherlands. 400 invalid_vat_id, invalid_country or invalid_buyer",
          "properties": {
           "vat_id": {
            "type": "string",
            "description": "EU VAT ID with its country prefix",
            "example": "DE123456789"
           },
           "country": {
            "type": "string",
            "description": "Two-letter code of your business's country",
            "example": "US"
           },
           "company": {
            "type": "string",
            "description": "Business name for the invoice"
           },
           "address": {
            "type": "string",
            "description": "Postal address for the invoice, one line"
           }
          }
         },
         "agent": {
          "type": "string",
          "description": "Without a key: your name as an agent, kept on the new account"
         },
         "force": {
          "type": "boolean",
          "description": "Top up although the balance isn't low, or make another account from the same address"
         }
        },
        "required": [
         "amount_usd"
        ]
       }
      }
     }
    },
    "x-payment-info": {
     "price": {
      "mode": "dynamic",
      "currency": "USD",
      "min": "5.00",
      "max": "50.00"
     },
     "protocols": [
      {
       "x402": {}
      },
      {
       "mpp": {
        "method": "evm",
        "intent": "charge",
        "currency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
       }
      },
      {
       "mpp": {
        "method": "tempo",
        "intent": "charge",
        "currency": "0x20C000000000000000000000b9537d11c60E8b50"
       }
      },
      {
       "mpp": {
        "method": "stripe",
        "intent": "charge",
        "currency": "usd"
       }
      }
     ],
     "offers": [
      {
       "method": "stripe",
       "intent": "charge",
       "amount": "500",
       "currency": "usd",
       "description": "$5 by card, through a Stripe Shared Payment Token: 500 calls"
      },
      {
       "method": "evm",
       "intent": "charge",
       "amount": "5000000",
       "currency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
       "description": "$5 in USDC on Base (MPP evm, or x402 exact): 500 calls"
      },
      {
       "method": "tempo",
       "intent": "charge",
       "amount": "5000000",
       "currency": "0x20C000000000000000000000b9537d11c60E8b50",
       "description": "$5 in USDC on Tempo: 500 calls"
      },
      {
       "method": "stripe",
       "intent": "charge",
       "amount": "2000",
       "currency": "usd",
       "description": "$20 by card, through a Stripe Shared Payment Token: 2,000 calls"
      },
      {
       "method": "evm",
       "intent": "charge",
       "amount": "20000000",
       "currency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
       "description": "$20 in USDC on Base (MPP evm, or x402 exact): 2,000 calls"
      },
      {
       "method": "tempo",
       "intent": "charge",
       "amount": "20000000",
       "currency": "0x20C000000000000000000000b9537d11c60E8b50",
       "description": "$20 in USDC on Tempo: 2,000 calls"
      },
      {
       "method": "stripe",
       "intent": "charge",
       "amount": "5000",
       "currency": "usd",
       "description": "$50 by card, through a Stripe Shared Payment Token: 5,000 calls"
      },
      {
       "method": "evm",
       "intent": "charge",
       "amount": "50000000",
       "currency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
       "description": "$50 in USDC on Base (MPP evm, or x402 exact): 5,000 calls"
      },
      {
       "method": "tempo",
       "intent": "charge",
       "amount": "50000000",
       "currency": "0x20C000000000000000000000b9537d11c60E8b50",
       "description": "$50 in USDC on Tempo: 5,000 calls"
      }
     ]
    },
    "responses": {
     "200": {
      "description": "Paid: the balance, the payment, its receipt (and a new account's key)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CreditTopup"
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "402": {
      "description": "Payment Required: the challenges in WWW-Authenticate (MPP: Payment, method stripe, tempo or evm) and PAYMENT-REQUIRED (x402 v2, exact, USDC on Base), and a body with error payment_required, what it buys, accepts (the rails on now), fix and, in Stripe's test mode, test_mode: true",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PaymentRequired"
        }
       }
      }
     },
     "409": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "422": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "502": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/credits": {
   "get": {
    "operationId": "credits",
    "summary": "Your prepaid credit for paid calls: the balance, the calls it pays, when it expires, each top-up with its receipt and unused part, and the history (calls by day, refunds, expiry)",
    "responses": {
     "200": {
      "description": "The credit",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Credit"
        }
       }
      }
     },
     "401": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/credits/rotate": {
   "post": {
    "operationId": "rotateKey",
    "summary": "A new key for the same account; the key you send stops working at once. The credit stays with the account",
    "security": [
     {
      "apiKey": []
     }
    ],
    "responses": {
     "200": {
      "description": "The new key, shown once, and the credit",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "api_key": {
           "type": "string"
          },
          "revoked": {
           "type": "string"
          },
          "credit": {
           "type": "object",
           "description": "The account's credit after this call",
           "properties": {
            "balance_cents": {
             "type": "integer"
            },
            "calls_left": {
             "type": "integer"
            },
            "expires_at": {
             "type": [
              "string",
              "null"
             ],
             "format": "date-time"
            },
            "paid_cents": {
             "type": "integer",
             "description": "What this call took"
            },
            "low": {
             "type": "boolean",
             "description": "50 calls left or fewer: time to top up"
            },
            "topup": {
             "type": "object",
             "description": "How to top up, when low"
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/credits/{id}/receipt": {
   "get": {
    "operationId": "topUpReceipt",
    "summary": "A top-up's receipt: the price, the VAT inside it and the payment, as a page to keep or print; ?download=1 as a file. No key needed: the top-up's id is enough. A business whose VAT ID VIES confirmed finds our invoice linked from it",
    "security": [],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "download",
      "in": "query",
      "required": false,
      "schema": {
       "enum": [
        "1"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The receipt",
      "content": {
       "text/html": {
        "schema": {
         "type": "string"
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/me": {
   "get": {
    "operationId": "me",
    "summary": "Your account, claims and orders",
    "responses": {
     "200": {
      "description": "Account",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Me"
        }
       }
      }
     },
     "401": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/me/delete": {
   "get": {
    "operationId": "deletePreview",
    "summary": "What deleting your account does now: the paid drives not run yet that are cancelled and refunded (refunds), the free checks cancelled, the subscriptions that end, and what stays. The delete itself: POST /api/auth/delete-user",
    "responses": {
     "200": {
      "description": "What a deletion does",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "refunds": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "order": {
              "type": "string"
             },
             "product": {
              "type": "string"
             },
             "domain": {
              "type": "string"
             },
             "amount_cents": {
              "type": "integer"
             },
             "running": {
              "type": "boolean"
             }
            }
           }
          },
          "checks_cancelled": {
           "type": "integer"
          },
          "subscriptions": {
           "type": "integer"
          },
          "line": {
           "type": [
            "string",
            "null"
           ]
          },
          "kept": {
           "type": "string"
          },
          "next": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/claims": {
   "post": {
    "operationId": "claimDomain",
    "summary": "Step 1, claim: add your product's domain. A verified sign-in email on the domain (or a subdomain or parent of it) verifies at once, unless the domain is a mailbox provider's (gmail.com, tuta.com …) and queues the free check (private); otherwise you get the ways to prove it (a code mailed to any address at the domain, a DNS TXT record, a meta tag on the home page or a file at /.well-known/agentdrive-verify.txt).",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "domain": {
          "type": "string",
          "example": "yourproduct.com"
         },
         "tool": {
          "type": "string",
          "description": "Directory slug, if listed"
         },
         "scan": {
          "type": "boolean",
          "default": true,
          "description": "false: don't queue the free check when the claim verifies"
         }
        },
        "required": [
         "domain"
        ]
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Claim, and the ways to verify it or the scan it queued",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "claim": {
           "$ref": "#/components/schemas/Claim"
          },
          "methods": {
           "$ref": "#/components/schemas/Methods"
          },
          "scan": {
           "$ref": "#/components/schemas/ScanQueued"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/claims/{id}/email": {
   "post": {
    "operationId": "emailClaimCode",
    "summary": "Step 2, one way to verify: mail a 6-digit code (valid 30 minutes) to an address at the domain; not on a mailbox provider's domain (409 not_possible). At most 3 codes an hour per account and per domain",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "local": {
          "type": "string",
          "example": "jane",
          "description": "The part before @, e.g. jane or one of admin, administrator, hostmaster, postmaster, webmaster"
         }
        },
        "required": [
         "local"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Code sent",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "sent_to": {
           "type": "string"
          },
          "next": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/claims/{id}/drive-stop": {
   "get": {
    "operationId": "getDriveStop",
    "summary": "Whether our drives of your product are stopped now (a verified claim)",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The stop",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DriveStop"
        }
       }
      }
     },
     "403": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   },
   "post": {
    "operationId": "setDriveStop",
    "summary": "Stop our drives of your own product, or let them start again. Published results stay, with their date; your own orders still run",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "stop": {
          "type": "boolean",
          "description": "true: stop our drives; false: let them start again"
         }
        },
        "required": [
         "stop"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The stop now",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DriveStop"
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/claims/{id}/verify": {
   "post": {
    "operationId": "verifyClaim",
    "summary": "Step 2, verify: with code, check the mailed code; without, check the DNS TXT record, then the meta tag, then the file. A newly verified product gets its free check queued (private: it lists nothing)",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "code": {
          "type": "string",
          "pattern": "^[0-9]{6}$",
          "description": "The code from POST /api/claims/{id}/email"
         },
         "scan": {
          "type": "boolean",
          "default": true
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Verified",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "claim": {
           "$ref": "#/components/schemas/Claim"
          },
          "scan": {
           "$ref": "#/components/schemas/ScanQueued"
          }
         }
        }
       }
      }
     },
     "409": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/orders": {
   "get": {
    "operationId": "listOrders",
    "summary": "Your orders",
    "responses": {
     "200": {
      "description": "Orders"
     }
    }
   },
   "post": {
    "operationId": "order",
    "summary": "Step 3 of 3, order for your product (prices before tax; the whole offer: https://agentdrives.com/pricing.json). The free check (free, $0): what an agent sees, in minutes: what it finds without a browser, the wall it would likely hit, the 3 first fixes, how the driven products in your category did and whether the product can be listed; private, never in the directory; any signed-in account, no domain proof; offers_ok: true only if you want the monthly report and offers; one per domain every 90 days (within them the call answers with the domain's latest check and next_free_at, no new check), 3 a day per account and a daily budget for everyone (429). A Drive (drive, $49 a drive): our agent drives your product the way it drives every product in the directory, the complete drive: up to 600 pages of docs read and judged, every way in tried (one account each, all deleted after), your core tasks read back, the checkout walked to the last click and one paid call of at most $1 where the product sells per call, cancel, delete, the crash test and which agents get past the bot check; your level, a dated Driven badge, the replay and a private report with the three fixes that move the level most; listed in the directory with its level unless listed: false; Docs match is measured in an Audit. An Audit (audit, $299): a Drive plus every documented API route, MCP tool and CLI command checked against your docs and a security review checked by a reviewer agent (security_ok: true is your go-ahead), up to 3 rivals (rivals: URLs or directory slugs; each driven on the agent path unless the directory drove it in the last 60 days, robots.txt honoured, compared with you privately), the full private report and a second drive within 30 days (followup_drive); your paid plan at cost is optional (plan); fair use: one product, up to about 3 hours of driving, a fixed sampling order on very large surfaces, and the report says what was sampled. Upgrade: upgrade_from is the id of your Drive whose report is at most 30 days old; the Audit then costs $250, once (409 upgrade_not_possible, already_upgraded or upgrade_expired). The Monthly drive (monthly, $29 a month; yearly, $290 a year): for a product in the directory with a verified claim (409 not_listed), our agent drives its path every month and you hear when the level or the place it stops changes; Driven monthly on the listing while it runs; one per product (409 already_kept); 10 or more by arrangement (409 talk_to_us); cancel any time (cancel_monthly), the listing stays. A paid drive is labelled Owner-paid drive. Also a Stack check (stack3 $490, stack $1,490) or a data plan (builder $49 a month, team $290 a month). A Stack check's tool or a rival whose owner asked us to stop driving it: 409 drive_stopped. Orders for your own product need a verified claim on its domain (else 403 claim_not_verified, with the claim and the ways to verify it). When online payment is on, payment.url is returned: open it to pay. Ordering the same thing again while it waits for payment answers 200 with that order (reused: true) and its checkout, never a second order; POST /api/orders/{id}/checkout opens it again too. A Drive also returns payment.agent: an agent pays it over HTTP 402 (MPP or x402, POST /api/orders/{id}/pay) without a person; an agent's own account (POST /api/agents/signup) pays only that way. By ordering you agree to the terms (https://agentdrives.com/legal/terms; privacy: https://agentdrives.com/legal/privacy); the order records their date. AgentDrives is for businesses: a paid order takes business: true to confirm you buy for your business (Stripe's checkout asks the business name, billing address and VAT ID), and no_offers: true to get no offers for our other products.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "product": {
          "enum": [
           "free",
           "drive",
           "audit",
           "monthly",
           "yearly",
           "stack",
           "stack3",
           "builder",
           "team",
           "quick",
           "verified_month",
           "verified"
          ],
          "description": "free: Free check · drive: Drive · audit: Audit · monthly: Monthly drive, monthly · yearly: Monthly drive, yearly · stack/stack3: Stack check · builder/team: data plans. Older ids still work: quick (Drive), verified_month and verified (Monthly drive). Orders answer with the ids above; whoami's orders keep the stored ones (quick a Drive, drive an Audit)"
         },
         "offers_ok": {
          "type": "boolean",
          "default": false,
          "description": "free: true only if you want the monthly agent access report and offers"
         },
         "rivals": {
          "type": "array",
          "maxItems": 3,
          "items": {
           "type": "string"
          },
          "description": "audit (the Audit): up to 3 rival products, as URLs or directory slugs (not your own domain), compared with you privately"
         },
         "upgrade_from": {
          "type": "string",
          "description": "product audit: your Drive whose report is at most 30 days old; it counts toward the Audit, once. The product is that order's"
         },
         "tool": {
          "type": "string"
         },
         "url": {
          "type": "string",
          "format": "uri"
         },
         "urls": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "description": "Stack check: the tools to drive (stack3: up to 3; stack: 5 included, up to 10)"
         },
         "use_case": {
          "type": "string",
          "description": "Stack check: what your agents should do with the tools"
         },
         "note": {
          "type": "string"
         },
         "listed": {
          "type": "boolean",
          "default": true,
          "description": "false: the drive stays private, never in the directory"
         },
         "access": {
          "type": "string",
          "description": "Optional: a test account, key, sandbox or coupon our agent may use past your sign-up wall"
         },
         "pay": {
          "type": "object",
          "required": [
           "kind"
          ],
          "description": "Let our agent buy your plan, at your own checkout (a Drive, an Audit or the Monthly drive). kind code: a one-use 100% off code; sandbox: a login to your checkout's test mode or sandbox; seat: no value, we send you our test account's address once our agent has signed up, and you upgrade it. Sealed, never shown back, deleted after the drive that used it",
          "properties": {
           "kind": {
            "enum": [
             "code",
             "sandbox",
             "seat"
            ]
           },
           "value": {
            "type": "string",
            "description": "code: 6 to 64 letters, digits, dots, dashes or underscores; sandbox: the login, up to 2,000 characters"
           }
          }
         },
         "buyer": {
          "type": "object",
          "description": "Optional, a Drive paid over HTTP 402: for our invoice. The price includes any VAT. An EU VAT ID that VIES confirms gets our invoice at once, with no VAT outside the Netherlands. 400 invalid_vat_id, invalid_country or invalid_buyer",
          "properties": {
           "vat_id": {
            "type": "string",
            "description": "EU VAT ID with its country prefix",
            "example": "DE123456789"
           },
           "country": {
            "type": "string",
            "description": "Two-letter code of your business's country",
            "example": "US"
           },
           "company": {
            "type": "string",
            "description": "Business name for the invoice"
           },
           "address": {
            "type": "string",
            "description": "Postal address for the invoice, one line"
           }
          }
         },
         "security_ok": {
          "type": "boolean",
          "description": "Your go-ahead for the Audit's security review of the agent surfaces, on our own test account (required for audit)"
         },
         "business": {
          "type": "boolean",
          "description": "Paid orders: true confirms you buy for your business. AgentDrives sells to businesses only (https://agentdrives.com/legal/terms#business); the order records it. Stripe's checkout asks the business name, billing address and VAT ID for the invoice"
         },
         "no_offers": {
          "type": "boolean",
          "default": false,
          "description": "Paid orders: true and we send you no offers for our other products"
         },
         "plan": {
          "type": "object",
          "description": "The Audit only: the owner's paid plan. The drive buys it, uses one paid feature, cancels it and asks for the refund the product's own way; the report's Paid plan section says what worked. choice include: the plan at cost is its own line on this order, and what the drive doesn't spend is refunded after the drive; self_refund: no line, you refund the drive's purchase yourself, at most $50 a month (above it 400 plan_needs_person: choose include, or write to us); none: no plan. name and price_cents (a month, in US cents) are the plan as your pricing page says (GET /api/me claims[].plan_hint suggests one); the drive spends at most that. Above $50 a month send confirm: true (else 400 plan_confirm_required); above $500 by arrangement (400 plan_too_expensive). Not on the Drive or the Monthly drive (400 invalid_plan)",
          "required": [
           "choice"
          ],
          "properties": {
           "choice": {
            "enum": [
             "include",
             "self_refund",
             "none"
            ]
           },
           "name": {
            "type": "string",
            "maxLength": 120
           },
           "price_cents": {
            "type": "integer",
            "minimum": 100
           },
           "source": {
            "enum": [
             "pricing",
             "owner"
            ],
            "description": "pricing: you kept our suggestion (plan_hint); owner: you typed it"
           },
           "confirm": {
            "type": "boolean"
           }
          }
         }
        },
        "required": [
         "product"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "free, within 90 days of the domain's last finished free check (any account): no new check; the latest one and when the next free one opens. A paid order while the same one waits for payment: that order (reused: true), its checkout in payment.url",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/FreeCheckExisting"
        }
       }
      }
     },
     "201": {
      "description": "Order",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "order": {
           "$ref": "#/components/schemas/Order"
          },
          "monthly": {
           "type": "object",
           "description": "The Monthly drive, when ordered: the day it starts",
           "properties": {
            "starts": {
             "type": "string",
             "format": "date-time"
            }
           }
          },
          "payment": {
           "type": [
            "object",
            "null"
           ],
           "properties": {
            "url": {
             "type": "string"
            }
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "invalid_product, ambiguous_product (drive with security_ok, rivals or plan: drive is the Drive, audit the Audit), product_retired (bench: the Audit has the rivals now), go_ahead_required (audit without security_ok: true), invalid_keep (the Monthly drive is its own order), invalid_rivals, invalid_plan, plan_confirm_required, plan_needs_person, plan_too_expensive, invalid_url, or another invalid field",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "not_your_product or claim_not_verified (every order but the free check): prove the domain is yours first; the body carries the fix, the claim and the ways to verify it",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "not_found: upgrade_from is not one of your orders",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "not_listed (the Monthly drive is for a product in the directory), already_kept, talk_to_us (10 or more), upgrade_not_possible, not_ready, already_upgraded, upgrade_expired, site_unreachable, flagged_unsafe or check_running (free check: the domain is being checked right now), drive_stopped (a Stack check's tool or an Audit's rival whose owner asked us to stop driving it: name another)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "billing_unavailable: online payment is switched off for a moment (paid products only; nothing was ordered or charged). Try again later",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/orders/{id}/followup": {
   "post": {
    "operationId": "followupDrive",
    "summary": "The second drive that comes with an Audit, within 30 days of its report (a Drive has none: 409 not_included). It retests what failed, then continues where the first drive stopped. Prove a fix, or pass access so the agent measures past your sign-up",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "access": {
          "type": "string"
         }
        }
       }
      }
     }
    },
    "responses": {
     "202": {
      "description": "Queued"
     },
     "403": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/suggest": {
   "post": {
    "operationId": "suggestProduct",
    "summary": "Suggest a product for our agent to drive and list (free, anyone): a signal for our planner, never a promise or a place in the queue.",
    "security": [],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "url": {
          "type": "string",
          "description": "The product's address or name"
         },
         "email": {
          "type": "string"
         },
         "why": {
          "type": "string"
         }
        },
        "required": [
         "url"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Recorded"
     }
    }
   }
  },
  "/api/orders/{id}/pay": {
   "post": {
    "operationId": "payCode",
    "summary": "Let our agent buy your plan: add or replace the code, test-mode login or seat on your order, until a drive has it (409 pay_in_use while one does; 409 order_closed once its drive is over)",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "kind"
        ],
        "description": "Let our agent buy your plan, at your own checkout (a Drive, an Audit or the Monthly drive). kind code: a one-use 100% off code; sandbox: a login to your checkout's test mode or sandbox; seat: no value, we send you our test account's address once our agent has signed up, and you upgrade it. Sealed, never shown back, deleted after the drive that used it",
        "properties": {
         "kind": {
          "enum": [
           "code",
           "sandbox",
           "seat"
          ]
         },
         "value": {
          "type": "string",
          "description": "code: 6 to 64 letters, digits, dots, dashes or underscores; sandbox: the login, up to 2,000 characters"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Stored",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "pay": {
           "type": [
            "object",
            "null"
           ],
           "description": "What you gave so our agent buys your plan: never the value",
           "properties": {
            "kind": {
             "enum": [
              "code",
              "sandbox",
              "seat"
             ]
            },
            "hint": {
             "type": [
              "string",
              "null"
             ],
             "description": "A code's last two characters"
            },
            "status": {
             "enum": [
              "waiting",
              "handed",
              "done",
              "removed"
             ],
             "description": "waiting: kept for the drive; handed: a drive has it now; done: that drive ended and it is deleted; removed: you removed it, or the order ended first"
            },
            "at": {
             "type": [
              "string",
              "null"
             ],
             "format": "date-time"
            },
            "mailed_at": {
             "type": [
              "string",
              "null"
             ],
             "format": "date-time",
             "description": "A seat: when we sent you our test account's address"
            }
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   },
   "delete": {
    "operationId": "removePayCode",
    "summary": "Delete the code or login on your order now",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Removed",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "pay": {
           "type": [
            "object",
            "null"
           ],
           "description": "What you gave so our agent buys your plan: never the value",
           "properties": {
            "kind": {
             "enum": [
              "code",
              "sandbox",
              "seat"
             ]
            },
            "hint": {
             "type": [
              "string",
              "null"
             ],
             "description": "A code's last two characters"
            },
            "status": {
             "enum": [
              "waiting",
              "handed",
              "done",
              "removed"
             ],
             "description": "waiting: kept for the drive; handed: a drive has it now; done: that drive ended and it is deleted; removed: you removed it, or the order ended first"
            },
            "at": {
             "type": [
              "string",
              "null"
             ],
             "format": "date-time"
            },
            "mailed_at": {
             "type": [
              "string",
              "null"
             ],
             "format": "date-time",
             "description": "A seat: when we sent you our test account's address"
            }
           }
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/pay-check": {
   "post": {
    "operationId": "payCheck",
    "summary": "The free checkout test. Test your checkout: Add a code and our agent buys your plan with it. A short private drive of your product's pay step: our agent signs up, buys your plan with the code (or in your checkout's test mode), uses one paid feature, cancels and deletes the account. Free for a product you've proved yours; one you've added but not proved counts with the free checks (429 rate_limited, scan_budget_reached), and its report opens once it's proved. One at a time per domain, its subdomains included (409 check_running), 2 per domain every 30 days (429 rate_limited with next_at), and a ceiling on all pay checks a day (429 rate_limited). 403 not_your_product: add the domain first (POST /api/claims); 403 claim_not_verified: a login (kind sandbox) needs the product proved yours, a code doesn't",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "url": {
          "type": "string",
          "format": "uri"
         },
         "tool": {
          "type": "string",
          "description": "Or your product's directory slug"
         },
         "pay": {
          "type": "object",
          "required": [
           "kind"
          ],
          "description": "Let our agent buy your plan, at your own checkout (a Drive, an Audit or the Monthly drive). kind code: a one-use 100% off code; sandbox: a login to your checkout's test mode or sandbox. Sealed, never shown back, deleted after the drive that used it",
          "properties": {
           "kind": {
            "enum": [
             "code",
             "sandbox"
            ]
           },
           "value": {
            "type": "string",
            "description": "code: 6 to 64 letters, digits, dots, dashes or underscores; sandbox: the login, up to 2,000 characters"
           }
          }
         }
        },
        "required": [
         "pay"
        ]
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Queued",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "order": {
           "$ref": "#/components/schemas/Order"
          },
          "note": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/orders/{id}/checkout": {
   "post": {
    "operationId": "checkoutOrder",
    "summary": "Pay an order that waits for payment (status requested): its Stripe Checkout while it is open, else a new one for the same order. A person opens payment.url; an agent's own account pays over HTTP 402 instead (POST /api/orders/{id}/payment)",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Where to pay",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "order": {
           "type": "object",
           "properties": {
            "id": {
             "type": "string"
            },
            "product": {
             "type": "string"
            },
            "status": {
             "type": "string"
            }
           }
          },
          "payment": {
           "type": "object",
           "properties": {
            "url": {
             "type": "string"
            }
           }
          },
          "reopened": {
           "type": "boolean",
           "description": "true: the same checkout as before; false: a new one for the same order"
          }
         }
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "not_payable (paid, withdrawn or not a paid order), payment_under_way, upgrade_expired, pay_over_402 (an agent's own account), billing_offline",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "description": "billing_unavailable",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/orders/{id}/withdraw": {
   "post": {
    "operationId": "withdrawOrder",
    "summary": "Withdraw an order that has not been paid",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Withdrawn"
     },
     "409": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/subscribe": {
   "post": {
    "operationId": "subscribe",
    "summary": "Subscribe to the monthly report (double opt-in: a confirmation mail is sent; signed in with the same verified address, it is confirmed at once and the answer says confirmed: true). source=launch: the launch list instead, one email at launch",
    "security": [],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "email": {
          "type": "string"
         },
         "source": {
          "type": "string"
         }
        },
        "required": [
         "email"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Confirmation mail sent, or confirmed at once"
     }
    }
   }
  },
  "/api/unsubscribe": {
   "get": {
    "operationId": "unsubscribe",
    "summary": "Unsubscribe (link in every mail)",
    "security": [],
    "parameters": [
     {
      "name": "e",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "t",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Unsubscribed"
     }
    }
   }
  },
  "/api/billing/cancel": {
   "post": {
    "operationId": "cancelMonthlyDrive",
    "summary": "Cancel the Monthly drive (or a subscription from before 10 Oct 2026) for one product (order_id) or all: no further charges; it stops at the end of the paid period. The listing stays",
    "requestBody": {
     "required": false,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "order_id": {
          "type": "string"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Cancelled"
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/billing/switch": {
   "post": {
    "operationId": "switchMonthlyDrive",
    "summary": "Switch the Monthly drive for one product between monthly ($29) and yearly ($290); the change is prorated and invoiced at once",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "order_id": {
          "type": "string"
         },
         "to": {
          "enum": [
           "month",
           "year"
          ]
         }
        },
        "required": [
         "order_id",
         "to"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Switched"
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "409": {
      "description": "cancelling: undo the cancellation first; legacy_plan: a subscription from before 10 Oct 2026 keeps its price",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/billing/portal": {
   "post": {
    "operationId": "billingPortal",
    "summary": "A link to invoices and payment methods",
    "responses": {
     "200": {
      "description": "Portal URL"
     }
    }
   }
  },
  "/api/auth/delete-user": {
   "post": {
    "operationId": "deleteAccount",
    "summary": "Delete your account and its data; every key stops working at once. With a session, one call. With your API key (x-api-key), two: the first answers 202 with a confirm token (and the paid drives not run yet that the deletion cancels and refunds), the same call with {token} within 5 minutes deletes. GET /api/me/delete says beforehand what it cancels and refunds",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "token": {
          "type": "string",
          "description": "With an API key: the confirm token the first call answered"
         }
        },
        "required": []
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Deleted: what went, the paid drives not run yet that were cancelled and refunded, what stays",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "success": {
           "type": "boolean"
          },
          "deleted": {
           "type": "boolean"
          },
          "gone": {
           "type": "string"
          },
          "refunds": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "order": {
              "type": "string"
             },
             "product": {
              "type": "string"
             },
             "domain": {
              "type": "string"
             },
             "amount_cents": {
              "type": "integer"
             },
             "refund": {
              "enum": [
               "made",
               "by_hand"
              ]
             }
            }
           }
          },
          "kept": {
           "type": "string"
          },
          "next": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "202": {
      "description": "With an API key: send the same call with this token to delete",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "confirm": {
           "const": "required"
          },
          "token": {
           "type": "string"
          },
          "expires_at": {
           "type": "string",
           "format": "date-time"
          },
          "refunds": {
           "type": "array",
           "items": {
            "type": "object"
           }
          },
          "note": {
           "type": "string"
          },
          "next": {
           "type": "string"
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "401": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/support/ask": {
   "post": {
    "operationId": "supportAsk",
    "summary": "Ask our support a question (prices, plans, levels, the method, your orders, the API and MCP). When our published pages answer it, the answer comes at once, quoted, with every source's id, text and URL (answered: true). When they don't, a case opens (answered: false, case_id; without a key also a case_token) and the answer comes in writing, in the case's status. Never promised here: a level, a refund or a date we don't control. No key needed: 20 questions an hour per address without one",
    "security": [
     {},
     {
      "apiKey": []
     },
     {
      "bearer": []
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "question": {
          "type": "string",
          "maxLength": 2000
         },
         "product": {
          "type": "string",
          "description": "The product's domain or directory slug it is about"
         },
         "on_behalf": {
          "type": "string",
          "description": "Whom you act for, kept on the case"
         }
        },
        "required": [
         "question"
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "An answer from our pages, or a case",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SupportAnswer"
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/support/disputes": {
   "post": {
    "operationId": "disputeResult",
    "summary": "Dispute your product's published result (a verified claim on its domain, else 403 claim_not_verified). A case opens; while no dispute re-drive of the product ran in the last 30 days, a confirm re-drive of the agent's path is queued (its result shows on the listing once reviewed). The answer comes in writing",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "product": {
          "type": "string",
          "description": "Your product's domain or directory slug"
         },
         "checkpoint": {
          "enum": [
           "docs",
           "signup",
           "verify",
           "credentials",
           "first_call",
           "first_action",
           "pay",
           "cancel",
           "delete"
          ]
         },
         "claim": {
          "type": "string",
          "maxLength": 2000
         },
         "evidence_url": {
          "type": "string",
          "description": "A public page that shows it (kept on the case, never fetched automatically)"
         }
        },
        "required": [
         "product",
         "checkpoint",
         "claim"
        ]
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "The case and the re-drive's state",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SupportCase"
        }
       }
      }
     },
     "401": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "403": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/support/cases/{id}": {
   "get": {
    "operationId": "caseStatus",
    "summary": "A support case: open, waiting (an answer is on its way), answered (with the answer) or closed; a dispute's re-drive. The key of the case's account, or the case_token of a case opened without a key",
    "security": [
     {},
     {
      "apiKey": []
     },
     {
      "bearer": []
     }
    ],
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "case_token",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The case",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/SupportCase"
        }
       }
      }
     },
     "404": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/tools.json": {
   "get": {
    "operationId": "listTools",
    "summary": "Every product in the directory (open data, CC BY 4.0): each one driven by our agent, with its agent level, part scores, drive date and origin (editorial or owner, with disclosure when the owner paid). Sorted by level, then work done, then minutes to the first call",
    "security": [],
    "responses": {
     "200": {
      "description": "Tools",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ToolList"
        }
       }
      }
     }
    }
   }
  },
  "/api/find-tools": {
   "get": {
    "operationId": "findToolsForTask",
    "summary": "Which products your agent can use for a task, ranked from our drives (the MCP tool find_tools_for_task): for each, the closest task in its capability map and what happened when our agent tried it, the agent level, whether our agent got in on its own, where it stopped, the work done, the drive date, origin (with disclosure when the owner paid) and the page. Strong matches first, then the ones our agent did, then level and work done. 120 requests per 10 minutes per IP",
    "security": [],
    "parameters": [
     {
      "name": "task",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      },
      "description": "What your agent should get done, in plain words, e.g. 'send an invoice'"
     },
     {
      "name": "category",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "A category id or name"
     },
     {
      "name": "self_signup",
      "in": "query",
      "schema": {
       "type": "boolean"
      },
      "description": "true: only products our agent signed up for and got a key on its own"
     },
     {
      "name": "min_level",
      "in": "query",
      "schema": {
       "$ref": "#/components/schemas/Level"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 25,
       "default": 10
      }
     }
    ],
    "responses": {
     "200": {
      "description": "The ranked products",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "task": {
           "type": "string"
          },
          "results": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/TaskResult"
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/registry/v0.1/servers": {
   "get": {
    "operationId": "registryServers",
    "summary": "Our levels in the MCP registry's v0.1 format, for catalogs that read a registry (base URL /api/registry): the MCP servers the official registry lists that belong to a product we drove, each with our level under _meta[\"com.agentdrives/drive\"]. Cursor pages as the v0.1 API; also /api/registry/v0.1/servers/{name}/versions and /versions/{version} (or latest)",
    "security": [],
    "parameters": [
     {
      "name": "cursor",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100,
       "default": 30
      }
     },
     {
      "name": "search",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Part of the server's name"
     },
     {
      "name": "updated_since",
      "in": "query",
      "schema": {
       "type": "string",
       "format": "date-time"
      }
     },
     {
      "name": "version",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "latest, or an exact version"
     }
    ],
    "responses": {
     "200": {
      "description": "A v0.1 ServerList: servers[] of {server, _meta}, metadata {count, nextCursor}"
     },
     "400": {
      "description": "Error with a machine-readable `error` and a `fix` that says what to do next",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/api/tools/{slug}.json": {
   "get": {
    "operationId": "getTool",
    "summary": "One drive with its evidence: the level, the five outcomes, the part scores, every checkpoint and every attempt",
    "security": [],
    "parameters": [
     {
      "name": "slug",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Drive",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Tool"
        }
       }
      }
     },
     "404": {
      "description": "not_found: no product with that slug; /api/tools.json lists every slug",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "apiKey": {
    "type": "apiKey",
    "in": "header",
    "name": "x-api-key"
   },
   "bearer": {
    "type": "http",
    "scheme": "bearer"
   }
  },
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "string"
     },
     "fix": {
      "type": "string"
     }
    },
    "required": [
     "error"
    ]
   },
   "ClaimLink": {
    "type": "object",
    "properties": {
     "url": {
      "type": "string",
      "format": "uri",
      "description": "For the person: open it and sign in"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time"
     },
     "how": {
      "type": "string"
     },
     "mailed_to": {
      "type": "string"
     },
     "mailed": {
      "type": "boolean"
     }
    }
   },
   "AgentSignup": {
    "type": "object",
    "properties": {
     "account": {
      "type": "object",
      "properties": {
       "id": {
        "type": "string"
       },
       "type": {
        "const": "agent"
       },
       "claimed": {
        "const": false
       }
      }
     },
     "api_key": {
      "type": "string",
      "description": "Shown once. Send it as x-api-key"
     },
     "key": {
      "type": "object",
      "properties": {
       "id": {
        "type": "string"
       },
       "start": {
        "type": "string"
       },
       "header": {
        "const": "x-api-key"
       }
      }
     },
     "limits": {
      "type": "object",
      "description": "What the account may do until a person claims it or it pays"
     },
     "claim": {
      "$ref": "#/components/schemas/ClaimLink"
     },
     "next": {
      "type": "array",
      "items": {
       "type": "string"
      }
     }
    }
   },
   "PaymentRequired": {
    "type": "object",
    "description": "The 402's body: the problem fields (type, title, status, detail, challengeId) and ours",
    "properties": {
     "error": {
      "const": "payment_required"
     },
     "fix": {
      "type": "string"
     },
     "order": {
      "type": "object",
      "properties": {
       "id": {
        "type": "string"
       },
       "product": {
        "type": "string"
       },
       "url": {
        "type": "string"
       },
       "price_cents": {
        "type": "integer"
       },
       "currency": {
        "type": "string"
       }
      }
     },
     "price_cents": {
      "type": "integer",
      "description": "Pay per call: the call's price"
     },
     "balance_cents": {
      "type": "integer",
      "description": "Pay per call with x-api-key: the key's credit (0: none left)"
     },
     "topup": {
      "type": "object",
      "description": "Pay per call: how to top up instead (url, amounts_usd, calls_per_usd, max_balance_usd, valid_months); a top-up: its amount and calls"
     },
     "accepts": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "rail": {
         "enum": [
          "mpp",
          "x402"
         ]
        },
        "method": {
         "type": "string"
        },
        "pays_with": {
         "type": "string"
        }
       }
      }
     },
     "test_mode": {
      "type": "boolean",
      "description": "Stripe's test mode: no real money moves"
     },
     "challengeId": {
      "type": "string"
     }
    }
   },
   "Credit": {
    "type": "object",
    "properties": {
     "balance_cents": {
      "type": "integer"
     },
     "calls_left": {
      "type": "integer"
     },
     "expires_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "currency": {
      "const": "usd"
     },
     "topups": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "id": {
         "type": "string"
        },
        "amount_cents": {
         "type": "integer"
        },
        "paid_with": {
         "enum": [
          "stripe",
          "tempo",
          "evm"
         ]
        },
        "paid_at": {
         "type": "string",
         "format": "date-time"
        },
        "refunded_cents": {
         "type": "integer"
        },
        "unused_cents": {
         "type": "integer"
        },
        "receipt_url": {
         "type": "string"
        }
       }
      }
     },
     "history": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "kind": {
         "enum": [
          "topup",
          "call",
          "refund",
          "expire",
          "adjust"
         ]
        },
        "at": {
         "type": "string",
         "format": "date-time"
        },
        "day": {
         "type": "string",
         "description": "Calls: the day they were made, summed"
        },
        "cents": {
         "type": "integer"
        },
        "calls": {
         "type": "integer"
        }
       }
      }
     },
     "rules": {
      "type": "object"
     },
     "open": {
      "type": "boolean",
      "description": "Whether top-ups are open now"
     }
    }
   },
   "CreditTopup": {
    "type": "object",
    "properties": {
     "account": {
      "type": "object",
      "properties": {
       "id": {
        "type": "string"
       },
       "type": {
        "const": "agent"
       }
      }
     },
     "api_key": {
      "type": "string",
      "description": "Without a key only: the new account's key, shown once (again only to the same Idempotency-Key)"
     },
     "claim": {
      "$ref": "#/components/schemas/ClaimLink"
     },
     "credit": {
      "type": "object",
      "description": "The account's credit after this call",
      "properties": {
       "balance_cents": {
        "type": "integer"
       },
       "calls_left": {
        "type": "integer"
       },
       "expires_at": {
        "type": [
         "string",
         "null"
        ],
        "format": "date-time"
       },
       "paid_cents": {
        "type": "integer",
        "description": "What this call took"
       },
       "low": {
        "type": "boolean",
        "description": "50 calls left or fewer: time to top up"
       },
       "topup": {
        "type": "object",
        "description": "How to top up, when low"
       }
      }
     },
     "topup": {
      "type": "object",
      "properties": {
       "id": {
        "type": "string"
       },
       "amount_cents": {
        "type": "integer"
       },
       "calls": {
        "type": "integer"
       }
      }
     },
     "payment": {
      "type": "object",
      "properties": {
       "rail": {
        "enum": [
         "mpp",
         "x402"
        ]
       },
       "method": {
        "enum": [
         "stripe",
         "tempo",
         "evm"
        ]
       },
       "amount_cents": {
        "type": "integer"
       },
       "reference": {
        "type": "string"
       },
       "payment_intent": {
        "type": [
         "string",
         "null"
        ]
       },
       "vat": {
        "type": "object"
       },
       "receipt_url": {
        "type": "string"
       },
       "invoice": {
        "type": [
         "object",
         "null"
        ]
       }
      }
     },
     "replayed": {
      "type": "boolean",
      "description": "The same Idempotency-Key again: this is the first answer, nothing was charged twice"
     },
     "next": {
      "type": "string"
     }
    }
   },
   "AgentPayment": {
    "type": "object",
    "properties": {
     "order": {
      "type": "object",
      "properties": {
       "id": {
        "type": "string"
       },
       "status": {
        "const": "paid"
       },
       "url": {
        "type": "string"
       },
       "drives_queued": {
        "type": "integer"
       }
      }
     },
     "payment": {
      "type": "object",
      "properties": {
       "rail": {
        "enum": [
         "mpp",
         "x402"
        ]
       },
       "method": {
        "enum": [
         "stripe",
         "tempo",
         "evm"
        ]
       },
       "amount_cents": {
        "type": "integer"
       },
       "currency": {
        "type": "string"
       },
       "reference": {
        "type": "string",
        "description": "A PaymentIntent id (a card) or a transaction hash"
       },
       "payment_intent": {
        "type": [
         "string",
         "null"
        ]
       },
       "mode": {
        "enum": [
         "test",
         "live"
        ]
       },
       "vat": {
        "type": "object",
        "description": "The VAT inside the price",
        "properties": {
         "category": {
          "enum": [
           "NL",
           "EU_RC",
           "EU_B2C",
           "NON_EU",
           "UNKNOWN"
          ]
         },
         "rate": {
          "type": "integer"
         },
         "vat_cents": {
          "type": "integer"
         },
         "net_cents": {
          "type": "integer"
         },
         "buyer_country": {
          "type": [
           "string",
           "null"
          ]
         },
         "vat_id": {
          "type": "string"
         },
         "vies": {
          "enum": [
           "valid",
           "invalid",
           "unavailable"
          ]
         }
        }
       },
       "receipt_url": {
        "type": "string",
        "description": "The payment's receipt, a page to keep or print"
       },
       "invoice": {
        "type": [
         "object",
         "null"
        ],
        "description": "Our invoice, for a business whose VAT ID VIES confirmed: number, url, pdf (pending: true while it is made)",
        "properties": {
         "number": {
          "type": "string"
         },
         "url": {
          "type": "string"
         },
         "pdf": {
          "type": "string"
         },
         "pending": {
          "type": "boolean"
         }
        }
       }
      }
     },
     "next": {
      "type": "string"
     },
     "test_mode": {
      "type": "boolean"
     }
    }
   },
   "TaskResult": {
    "type": "object",
    "description": "One product for a task (GET /api/find-tools, MCP find_tools_for_task)",
    "properties": {
     "slug": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "category": {
      "type": "string"
     },
     "level": {
      "$ref": "#/components/schemas/Level"
     },
     "level_name": {
      "type": "string"
     },
     "gets_in_alone": {
      "type": "boolean",
      "description": "Our agent signed up and got a key without a person"
     },
     "match": {
      "enum": [
       "strong",
       "partial"
      ]
     },
     "task": {
      "type": [
       "object",
       "null"
      ],
      "properties": {
       "matched": {
        "type": "string",
        "description": "The closest task in the product's capability map, or a thing our agent did there"
       },
       "result": {
        "enum": [
         "done",
         "partial",
         "plan_gated",
         "failed",
         "blocked",
         "not_tried",
         "unknown"
        ]
       },
       "via": {
        "type": "string",
        "description": "The route: api, mcp, cli, browser"
       }
      }
     },
     "can_do": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "stop": {
      "type": [
       "object",
       "null"
      ],
      "properties": {
       "at": {
        "type": "string"
       },
       "why": {
        "type": [
         "string",
         "null"
        ]
       }
      }
     },
     "work_done": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Share of the core tasks done, 0-100"
     },
     "tested_at": {
      "type": "string"
     },
     "url": {
      "type": "string"
     },
     "origin": {
      "enum": [
       "editorial",
       "owner"
      ]
     },
     "disclosure": {
      "type": "string"
     }
    }
   },
   "SupportAnswer": {
    "type": "object",
    "description": "An answer from our support agent: quoted from our published pages (answered), or a case we answer in writing",
    "properties": {
     "answered": {
      "type": "boolean"
     },
     "answer": {
      "type": "string"
     },
     "facts": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "id": {
         "type": "string"
        },
        "text": {
         "type": "string"
        },
        "url": {
         "type": "string"
        }
       }
      }
     },
     "case_id": {
      "type": "string"
     },
     "case_token": {
      "type": "string",
      "description": "Without a key: keep it to read the case"
     },
     "account": {
      "type": "object",
      "description": "With a key: your own orders and claims"
     },
     "by": {
      "type": "string",
      "description": "Who answers: AgentDrives support agent"
     }
    },
    "required": [
     "answered",
     "by"
    ]
   },
   "SupportCase": {
    "type": "object",
    "properties": {
     "case_id": {
      "type": "string"
     },
     "class": {
      "type": "string"
     },
     "state": {
      "enum": [
       "open",
       "waiting",
       "answered",
       "closed"
      ]
     },
     "next": {
      "type": "string"
     },
     "redrive": {
      "type": [
       "object",
       "null"
      ],
      "description": "A dispute's confirm re-drive: queued (state, queued_at) or why not"
     },
     "answer": {
      "type": [
       "string",
       "null"
      ],
      "description": "The answer, once a person approved it"
     },
     "answered_at": {
      "type": [
       "string",
       "null"
      ]
     },
     "by": {
      "type": "string"
     }
    }
   },
   "User": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "email": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "emailVerified": {
      "type": "boolean"
     }
    }
   },
   "DriveStop": {
    "type": "object",
    "properties": {
     "domain": {
      "type": "string"
     },
     "stopped": {
      "type": "boolean"
     },
     "since": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "covers": {
      "type": [
       "string",
       "null"
      ],
      "description": "The domain the stop is on (yours, or a parent of it)"
     }
    }
   },
   "Claim": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "domain": {
      "type": "string"
     },
     "tool_slug": {
      "type": [
       "string",
       "null"
      ]
     },
     "status": {
      "enum": [
       "pending",
       "verified"
      ]
     },
     "token": {
      "type": "string"
     },
     "listed": {
      "type": "boolean",
      "description": "GET /api/me: the product is in the directory"
     },
     "check": {
      "type": "object",
      "description": "GET /api/me, a proved domain only: its latest finished free check when another account ran it. You read its result at GET /api/orders/{order_id}/report",
      "properties": {
       "order_id": {
        "type": "string"
       },
       "checked_at": {
        "type": "string",
        "format": "date-time"
       },
       "next_free_at": {
        "type": "string",
        "format": "date-time"
       }
      }
     },
     "plan_hint": {
      "type": [
       "object",
       "null"
      ],
      "description": "GET /api/me: the product's cheapest paid plan from its pricing page as we last read it (checked), a suggestion for an order's plan; price_cents null when it isn't billed monthly",
      "properties": {
       "plan": {
        "type": "string"
       },
       "price_cents": {
        "type": [
         "integer",
         "null"
        ]
       },
       "per_seat": {
        "type": "boolean"
       },
       "monthly": {
        "type": [
         "boolean",
         "null"
        ]
       },
       "source": {
        "type": "string"
       },
       "checked": {
        "type": "string",
        "format": "date"
       }
      }
     }
    }
   },
   "Order": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "product": {
      "type": "string",
      "description": "The id you order with: free, drive (a Drive), audit (an Audit), monthly or yearly (the Monthly drive), stack, stack3, builder, team, pay_check. GET /api/me's orders keep the stored ids: quick a Drive, drive an Audit, verified_month or verified the Monthly drive"
     },
     "status": {
      "enum": [
       "requested",
       "paid",
       "queued",
       "running",
       "done",
       "failed",
       "past_due",
       "cancelled"
      ],
      "description": "past_due: a Monthly drive renewal failed; it is active again once paid. failed: paid, but the drive and its automatic retry failed; a person drives it again or refunds it"
     },
     "tool_slug": {
      "type": [
       "string",
       "null"
      ]
     },
     "url": {
      "type": [
       "string",
       "null"
      ]
     },
     "followup_available": {
      "type": "boolean"
     },
     "followups_left": {
      "type": "integer"
     },
     "rivals": {
      "type": [
       "array",
       "null"
      ],
      "items": {
       "type": "string"
      },
      "description": "An Audit: its rivals, compared privately"
     },
     "upgrade_from": {
      "type": [
       "string",
       "null"
      ],
      "description": "An upgrade: the order it builds on"
     },
     "upgraded_to": {
      "type": [
       "string",
       "null"
      ],
      "description": "This order was upgraded by that order"
     },
     "upgrades": {
      "type": "array",
      "description": "The upgrades open to this order, until 30 days after its report",
      "items": {
       "type": "object",
       "properties": {
        "to": {
         "enum": [
          "drive"
         ]
        },
        "price_cents": {
         "type": "integer"
        },
        "until": {
         "type": "string",
         "format": "date-time"
        }
       }
      }
     },
     "drive_order": {
      "type": [
       "string",
       "null"
      ],
      "description": "A subscription from before 10 Oct 2026 that came with a Drive: that order"
     },
     "keep_from": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time",
      "description": "The Monthly drive: the day it started"
     },
     "keep_cents": {
      "type": [
       "integer",
       "null"
      ],
      "description": "The Monthly drive: its price per period, excl. VAT"
     },
     "legacy_keep": {
      "type": "boolean",
      "description": "A subscription from before 10 Oct 2026: it keeps its price and terms until it ends"
     },
     "offers_ok": {
      "type": "boolean",
      "description": "A free check: the box for the monthly report and offers was ticked"
     },
     "pay": {
      "type": [
       "object",
       "null"
      ],
      "description": "What you gave so our agent buys your plan: never the value",
      "properties": {
       "kind": {
        "enum": [
         "code",
         "sandbox",
         "seat"
        ]
       },
       "hint": {
        "type": [
         "string",
         "null"
        ],
        "description": "A code's last two characters"
       },
       "status": {
        "enum": [
         "waiting",
         "handed",
         "done",
         "removed"
        ],
        "description": "waiting: kept for the drive; handed: a drive has it now; done: that drive ended and it is deleted; removed: you removed it, or the order ended first"
       },
       "at": {
        "type": [
         "string",
         "null"
        ],
        "format": "date-time"
       },
       "mailed_at": {
        "type": [
         "string",
         "null"
        ],
        "format": "date-time",
        "description": "A seat: when we sent you our test account's address"
       }
      }
     },
     "check_state": {
      "enum": [
       "failed",
       "late",
       null
      ],
      "description": "A free check: failed when it didn't finish (order it again: a check that didn't finish doesn't count against its domain's 90 days); late when it has waited longer than usual to start; null otherwise"
     },
     "terms": {
      "type": [
       "string",
       "null"
      ],
      "description": "The date of the terms the order was bought on (YYYY-MM-DD)"
     },
     "business": {
      "type": [
       "boolean",
       "null"
      ],
      "description": "A paid order: you confirmed you buy for your business"
     },
     "company": {
      "type": [
       "string",
       "null"
      ]
     },
     "vat_id": {
      "type": [
       "string",
       "null"
      ]
     },
     "plan_choice": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "include",
       "self_refund",
       "none",
       null
      ],
      "description": "The owner's paid plan on an Audit"
     },
     "plan_name": {
      "type": [
       "string",
       "null"
      ]
     },
     "plan_cents": {
      "type": [
       "integer",
       "null"
      ],
      "description": "The plan's monthly price: the drive's budget"
     },
     "plan_line_cents": {
      "type": "integer",
      "description": "What the plan line took at checkout (include)"
     },
     "plan_spent_cents": {
      "type": [
       "integer",
       "null"
      ],
      "description": "What the drive spent on the plan, net of what the product refunded"
     },
     "plan_refunded_cents": {
      "type": "integer",
      "description": "What went back of the plan line"
     },
     "plan_status": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "waiting",
       "bought",
       "not_bought",
       "settled",
       "by_hand",
       null
      ]
     },
     "plan_result": {
      "type": [
       "object",
       "null"
      ],
      "description": "What the drive recorded: bought, charged, currency, used, cancel, refund, charged_after_cancel"
     }
    }
   },
   "Methods": {
    "type": "object",
    "description": "Ways to prove the domain is yours",
    "properties": {
     "email": {
      "type": "object",
      "properties": {
       "how": {
        "type": "string"
       }
      }
     },
     "dns": {
      "type": "object",
      "properties": {
       "type": {
        "const": "TXT"
       },
       "name": {
        "type": "string"
       },
       "value": {
        "type": "string"
       },
       "then": {
        "type": "string"
       }
      }
     },
     "meta": {
      "type": "object",
      "properties": {
       "tag": {
        "type": "string"
       },
       "where": {
        "type": "string"
       },
       "then": {
        "type": "string"
       }
      }
     },
     "file": {
      "type": "object",
      "properties": {
       "url": {
        "type": "string"
       },
       "content": {
        "type": "string"
       },
       "then": {
        "type": "string"
       }
      }
     }
    }
   },
   "FreeCheckExisting": {
    "type": "object",
    "properties": {
     "order": {
      "type": "null"
     },
     "payment": {
      "type": "null"
     },
     "queued": {
      "const": false
     },
     "check": {
      "type": "object",
      "properties": {
       "domain": {
        "type": "string"
       },
       "checked_at": {
        "type": "string",
        "format": "date-time"
       },
       "yours": {
        "type": "boolean",
        "description": "true: your account ran it; its result: GET /api/orders/{order_id}/report. Another account's check stays private: only its date, unless you proved the domain (proved: true)"
       },
       "order_id": {
        "type": "string",
        "description": "only when yours, or when you proved the domain"
       },
       "proved": {
        "type": "boolean",
        "description": "true: you proved the domain, so you read its latest check whoever ran it"
       }
      }
     },
     "next_free_at": {
      "type": "string",
      "format": "date-time",
      "description": "when the domain's next free check opens: 90 days after this one"
     },
     "note": {
      "type": "string"
     }
    }
   },
   "ScanQueued": {
    "type": [
     "object",
     "null"
    ],
    "description": "The free check a newly verified claim queues (null when the claim was verified before)",
    "properties": {
     "queued": {
      "type": "boolean"
     },
     "order_id": {
      "type": "string"
     },
     "next_free_at": {
      "type": "string",
      "format": "date-time",
      "description": "with scanned_recently"
     },
     "reason": {
      "type": "string",
      "description": "Why not: scanned_recently, check_running, rate_limited, scan_budget_reached, site_unreachable, flagged_unsafe"
     },
     "fix": {
      "type": "string"
     }
    }
   },
   "Level": {
    "type": "integer",
    "minimum": 0,
    "maximum": 5,
    "description": "Agent level, the only rank: 0 Read-only (Agents can read about it, but there is nothing to use); 1 Needs a person (Agents can't get in on their own); 2 Gets in (An agent gets in on its own but does less than half the core work); 3 Does the work (An agent gets in on its own and does half the core work or more); 4 Runs on its own (An agent does the core work and can stop paying on its own); 5 Autonomous (All of that, and it pays on its own for the work)"
   },
   "Parts": {
    "type": "object",
    "description": "The part scores (methodology 15), 0-100, null when not measured; they never change the level and there is no total. Bands: 90+ good, 50-89 fair, under 50 poor. Pages show only the measured ones, and Agent-ready setup as what was found (llms.txt, OpenAPI, MCP, CLI: the surfaces), not as a number.",
    "properties": {
     "holds_up": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Reliability and the crash test. null until the crash test ran"
     },
     "docs_match": {
      "type": [
       "integer",
       "null"
      ],
      "description": "The docs checked against live behaviour (accuracy and completeness). null until the full surface audit ran"
     },
     "setup": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Agent-ready setup as points (kept for compatibility): machine-readable docs, OpenAPI, llms.txt, MCP, CLI or SDK. Pages show the surfaces found instead"
     },
     "security": {
      "const": "private",
      "description": "Security is reported privately to the owner, the same for every product: no score or count"
     },
     "standards": {
      "type": "array",
      "description": "Whether the product speaks the current version of each standard, as facts, never points",
      "items": {
       "type": "object",
       "properties": {
        "standard": {
         "type": "string",
         "example": "OpenAPI"
        },
        "state": {
         "enum": [
          "current",
          "behind"
         ]
        },
        "behind": {
         "type": [
          "integer",
          "null"
         ],
         "description": "Revisions behind, when countable"
        },
        "value": {
         "type": [
          "string",
          "null"
         ]
        }
       }
      }
     }
    }
   },
   "Stage": {
    "type": "object",
    "description": "One of the four stages that decide the level (in: Access, work: Use, pay: Pay, leave: Leave), by the level's own rules; the same four as outcomes 2-5 with their older keys. They sum up the agent's steps: Access is Sign up and Get a key (or a way in without an account), Use is Do the work, Pay is Pay, Leave is Cancel and Leave",
    "properties": {
     "key": {
      "enum": [
       "in",
       "work",
       "pay",
       "leave"
      ]
     },
     "label": {
      "type": "string"
     },
     "state": {
      "enum": [
       "yes",
       "part",
       "no",
       "unreached",
       "na"
      ]
     },
     "text": {
      "type": "string"
     },
     "value": {
      "enum": [
       "paid",
       "partial",
       "ready",
       "person",
       "not_tried",
       "unreached",
       "nothing"
      ],
      "description": "Pay only: paid (an agent-native payment we made and checked, x402 or MPP, that pays for the work: credits or a plan for its account, or per call for at least 80% of the core), partial (it pays per call, for less of the core than that), ready (the agent reached the checkout, the last step before the money, and paid nothing; with why unsettled, our side paid and the seller didn't settle), person (the product puts a person in the way of buying), not_tried (our side didn't try: no card, robots.txt, time, a rule; never the product's failure), unreached (an earlier wall), nothing (no plan to buy). The words are in text, and may change; the values stay"
     },
     "per_call": {
      "type": "object",
      "description": "Pay only, with a per-call payment: what the per-call route covers of the core (caps: the capability ids, core: the core's size, share: percent)",
      "properties": {
       "caps": {
        "type": "array",
        "items": {
         "type": "string"
        }
       },
       "core": {
        "type": "integer"
       },
       "share": {
        "type": [
         "integer",
         "null"
        ]
       }
      }
     },
     "left": {
      "enum": [
       "deleted",
       "data_only",
       "nothing_made",
       "removed",
       "expires",
       "stuck",
       "wallet_kept"
      ],
      "description": "Leave only: what the agent left behind. deleted: its account; data_only: the data and keys went, the login stayed; nothing_made, removed, expires (with after_hours): used without an account; stuck: it can't remove its account or what it made"
     },
     "after_hours": {
      "type": "number",
      "description": "Leave only, with expires: after how long the product removes what the agent made, per its docs"
     },
     "route": {
      "type": "string",
      "enum": [
       "agent_rail",
       "projects",
       "billing_api",
       "agent_checkout",
       "card_checkout",
       "portal",
       "sales",
       "none"
      ],
      "description": "Pays only: the most agentic way to buy the product offers"
     },
     "why": {
      "type": "string",
      "description": "Pays only: for person, what the product puts in the way (sales, quote, approval, captcha, phone, invoice, id_check, other); for not_tried, our reason (no_card, robots, time, rule, budget, yearly_only, cap, wallet, account); for ready, unsettled when our side paid and the seller didn't settle"
     },
     "way": {
      "type": "string",
      "description": "Access only: the way in the agent got in by, when the drive kept its route table (e.g. email_code, api_signup, sso_github)"
     }
    }
   },
   "Outcome": {
    "type": "object",
    "description": "One of the five outcomes (from the rules of 13 Oct 2026): what an agent needs from a product, whatever the route. find: can it discover the product and learn to use it (llms.txt, OpenAPI, its own MCP server, the docs read); shown first, it decides no level. access, use, pay, leave: the four stages, with the stage's own key in `stage`. A level's outcomes are met by construction: L2 needs access, L3 access and use at least part, L4 access, use and leave, L5 all four (pay na: nothing to pay counts). The other fields are the Stage's",
    "properties": {
     "key": {
      "enum": [
       "find",
       "access",
       "use",
       "pay",
       "leave"
      ]
     },
     "label": {
      "type": "string"
     },
     "state": {
      "enum": [
       "yes",
       "part",
       "no",
       "unreached",
       "na"
      ]
     },
     "text": {
      "type": "string"
     },
     "value": {
      "enum": [
       "paid",
       "partial",
       "ready",
       "person",
       "not_tried",
       "unreached",
       "nothing"
      ],
      "description": "Pay only: paid (an agent-native payment we made and checked, x402 or MPP, that pays for the work: credits or a plan for its account, or per call for at least 80% of the core), partial (it pays per call, for less of the core than that), ready (the agent reached the checkout, the last step before the money, and paid nothing; with why unsettled, our side paid and the seller didn't settle), person (the product puts a person in the way of buying), not_tried (our side didn't try: no card, robots.txt, time, a rule; never the product's failure), unreached (an earlier wall), nothing (no plan to buy). The words are in text, and may change; the values stay"
     },
     "per_call": {
      "type": "object",
      "description": "Pay only, with a per-call payment: what the per-call route covers of the core (caps: the capability ids, core: the core's size, share: percent)",
      "properties": {
       "caps": {
        "type": "array",
        "items": {
         "type": "string"
        }
       },
       "core": {
        "type": "integer"
       },
       "share": {
        "type": [
         "integer",
         "null"
        ]
       }
      }
     },
     "left": {
      "enum": [
       "deleted",
       "data_only",
       "nothing_made",
       "removed",
       "expires",
       "stuck",
       "wallet_kept"
      ],
      "description": "Leave only: what the agent left behind. deleted: its account; data_only: the data and keys went, the login stayed; nothing_made, removed, expires (with after_hours): used without an account; stuck: it can't remove its account or what it made"
     },
     "after_hours": {
      "type": "number",
      "description": "Leave only, with expires: after how long the product removes what the agent made, per its docs"
     },
     "route": {
      "type": "string",
      "enum": [
       "agent_rail",
       "projects",
       "billing_api",
       "agent_checkout",
       "card_checkout",
       "portal",
       "sales",
       "none"
      ],
      "description": "Pays only: the most agentic way to buy the product offers"
     },
     "why": {
      "type": "string",
      "description": "Pays only: for person, what the product puts in the way (sales, quote, approval, captcha, phone, invoice, id_check, other); for not_tried, our reason (no_card, robots, time, rule, budget, yearly_only, cap, wallet, account); for ready, unsettled when our side paid and the seller didn't settle"
     },
     "way": {
      "type": "string",
      "description": "Access only: the way in the agent got in by, when the drive kept its route table (e.g. email_code, api_signup, sso_github)"
     },
     "stage": {
      "type": "string",
      "enum": [
       "in",
       "work",
       "pay",
       "leave"
      ]
     },
     "have": {
      "type": "array",
      "items": {
       "enum": [
        "llms_txt",
        "openapi",
        "mcp"
       ]
      },
      "description": "Find only: what the drive found"
     },
     "docs": {
      "type": "string",
      "description": "Find only: the docs pass's verdict, when the drive read the docs"
     }
    }
   },
   "Access": {
    "type": "object",
    "description": "How an agent gets in (rules of 13 Oct 2026): one entry per way that got it in on its own, agent-native first; key person: none did",
    "properties": {
     "key": {
      "enum": [
       "keyless",
       "local",
       "try_first",
       "no_account",
       "pay_per_call",
       "key_by_api",
       "mcp_signin",
       "email_signup",
       "browser_signup",
       "by_name",
       "person"
      ]
     },
     "label": {
      "type": "string",
      "example": "Pay per call"
     },
     "routes": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "The route ids behind it (e.g. pay_per_call, email_code, sso_github)"
     },
     "minutes": {
      "type": [
       "number",
       "null"
      ],
      "description": "Minutes to the first call on this way"
     },
     "core": {
      "type": [
       "string",
       "null"
      ],
      "description": "Core tasks done on this way, as done/total",
      "example": "8/8"
     }
    }
   },
   "ToolSummary": {
    "type": "object",
    "description": "One product in /api/tools.json (the same fields open each /api/tools/{slug}.json)",
    "properties": {
     "slug": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "domain": {
      "type": "string"
     },
     "icon": {
      "type": [
       "string",
       "null"
      ],
      "description": "The product's logo, a path on this site"
     },
     "category": {
      "type": "string",
      "description": "The category id"
     },
     "category_name": {
      "type": "string"
     },
     "tested_at": {
      "type": "string",
      "format": "date",
      "description": "The day of the drive behind the level"
     },
     "url": {
      "type": "string",
      "format": "uri",
      "description": "The product's page here"
     },
     "json": {
      "type": "string",
      "format": "uri",
      "description": "Its full record: /api/tools/{slug}.json"
     },
     "draft": {
      "type": "boolean",
      "description": "Not reviewed yet: the result may still change"
     },
     "origin": {
      "enum": [
       "editorial",
       "owner"
      ],
      "description": "editorial: we picked the product; owner: its owner ordered the drive"
     },
     "disclosure": {
      "type": "string",
      "description": "Only on a drive its owner paid for: the label to show with it",
      "example": "Owner-paid drive"
     },
     "stale": {
      "type": "boolean",
      "description": "The newest drive is older than 182 days"
     },
     "level_selfhost": {
      "type": [
       "integer",
       "null"
      ],
      "description": "The level of the self-hosted edition, when it was driven (null: not driven)"
     },
     "summary": {
      "type": "string",
      "description": "What an agent can do with it, in a sentence or two"
     },
     "first_blocker": {
      "type": "string",
      "description": "The first thing that stops or slows an agent"
     },
     "coverage_source": {
      "enum": [
       "computed",
       "reported"
      ],
      "description": "computed: work done measured against the product's capability map; reported: counted by the driving agent"
     },
     "core": {
      "type": [
       "string",
       "null"
      ],
      "description": "Core features done of all, as done/total",
      "example": "8/8"
     },
     "pay": {
      "type": [
       "string",
       "null"
      ],
      "description": "The pay grade, P0 to P5 (n/a: nothing to pay for)",
      "example": "P2"
     },
     "lets_agent": {
      "type": [
       "string",
       "null"
      ],
      "description": "A bot check that let our signed agent through (null: none seen)"
     },
     "mcp": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "official",
       "third-party",
       "none",
       null
      ],
      "description": "Whether it has an MCP server: its own, someone else's, or none"
     },
     "level": {
      "$ref": "#/components/schemas/Level"
     },
     "level_name": {
      "type": "string",
      "example": "Does the work"
     },
     "parts": {
      "$ref": "#/components/schemas/Parts"
     },
     "stages": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Stage"
      }
     },
     "next": {
      "type": "object",
      "properties": {
       "to": {
        "type": [
         "integer",
         "null"
        ]
       },
       "text": {
        "type": "string"
       }
      }
     },
     "outcomes": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Outcome"
      },
      "description": "The five outcomes: find, access, use, pay, leave"
     },
     "access": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Access"
      },
      "description": "How an agent gets in"
     },
     "minutes": {
      "type": [
       "number",
       "null"
      ],
      "description": "Minutes to the first call on the fastest way in; within a level, the order after work done"
     },
     "stop": {
      "type": [
       "string",
       "null"
      ],
      "description": "The first checkpoint the agent did not get past (null: through every one). Only a stop at the door (signup, verify, credentials, first_call) ends a drive; past it each checkpoint is tested on its own"
     },
     "coverage_core": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Work done: the share of the core features done and read back, through documented routes (null: not measured)"
     },
     "entry": {
      "enum": [
       "self-start",
       "setup",
       "closed"
      ],
      "description": "self-start: gets in on its own; setup: a human set up the account once; closed: can't get in on its own. self-start and the other two add up to every product: the other two are the products that stop an agent at the door"
     },
     "badges": {
      "type": "array",
      "items": {
       "enum": [
        "agent-can-buy",
        "agent-can-leave"
       ]
      },
      "description": "agent-can-buy: an agent paid through an agent-native rail, proven from our side; agent-can-leave: leaves on its own"
     },
     "pays_with": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "The agent-native ways to pay it offers, from our pay probe or the drive (x402, mpp, l402, stripe-projects, acp, ucp, ap2, mcp-payment)"
     },
     "paid": {
      "type": "boolean",
      "description": "Our side made and proved a payment on one of them (the transaction is in the tool's pay_options.paid)"
     },
     "blocks_agent": {
      "type": [
       "string",
       "null"
      ],
      "description": "The bot check that stopped our signed agent on at least one way in, from sign-up to the first call (null: none did). With entry self-start it got in another way; otherwise the check stood in its way at the door"
     },
     "wall_type": {
      "enum": [
       "network",
       "challenge",
       null
      ],
      "description": "What kind of bot check it was. network: It judged where our agent connects from and its browser, not a person. An agent that works on its own from a data center doesn't get through unless the owner lets signed agents in. How agents in a person's own browser fare isn't measured yet. challenge: It asks every visitor to prove they are human. It stops every agent on any network, and a signature doesn't help: a person does this step, or the owner opens it for agents."
     },
     "monitored": {
      "type": "boolean",
      "description": "Driven monthly"
     },
     "freshness": {
      "enum": [
       "fresh",
       "aging",
       "redrive"
      ],
      "description": "How old the drive is: aging from 90 days (Driven over 3 months ago), redrive from 180 (Needs a new drive)"
     },
     "same_level_drives": {
      "type": "integer",
      "description": "The latest drives in a row that gave this level"
     },
     "drives": {
      "type": "integer",
      "description": "Every drive of the product so far"
     },
     "robots": {
      "$ref": "#/components/schemas/Robots"
     },
     "ways_in": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "The ways in that got our agent in (route ids, e.g. api_signup, sso_github); empty on drives before the route table"
     },
     "docs_overall": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "complete",
       "gaps",
       "thin",
       "unreachable",
       null
      ],
      "description": "The docs pass's verdict (null: no docs pass on that drive)"
     }
    }
   },
   "Robots": {
    "type": [
     "object",
     "null"
    ],
    "description": "robots.txt on the way in (null: no drive met a rule there). rule named: a rule that names our agent or AI agents that act for a user, the product's own wall; star: a rule for all user agents, a rule for crawlers and never the product's wall. held: the drives after the one shown stopped at a rule for all user agents while our agent follows it on account steps, so the level is that earlier drive's",
    "properties": {
     "rule": {
      "enum": [
       "named",
       "star"
      ]
     },
     "step": {
      "type": [
       "string",
       "null"
      ],
      "enum": [
       "signup",
       "verify",
       "credentials",
       "first_call",
       null
      ]
     },
     "seen": {
      "type": "string",
      "format": "date",
      "description": "The newest drive that met it"
     },
     "held": {
      "type": "boolean"
     }
    }
   },
   "ToolList": {
    "type": "object",
    "properties": {
     "methodology": {
      "type": "integer"
     },
     "rules_date": {
      "type": "string",
      "format": "date",
      "description": "The date of the rules the levels were set by"
     },
     "tools": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/ToolSummary"
      }
     }
    }
   },
   "Tool": {
    "allOf": [
     {
      "$ref": "#/components/schemas/ToolSummary"
     },
     {
      "type": "object",
      "properties": {
       "scores": {
        "type": "object",
        "description": "The measures behind the parts: coverage, reliability, resilience, setup, and after the full surface audit surface_coverage, docs_accuracy, docs_completeness"
       },
       "methodology": {
        "type": "integer",
        "description": "The scoring rules that made this result"
       },
       "rules_date": {
        "type": "string",
        "format": "date",
        "description": "The date of those rules, as pages name them (\"Rules of ...\"; now 2026-10-15). Every set of rules: /method/changelog"
       },
       "engine": {
        "type": [
         "object",
         "null"
        ],
        "description": "What made this drive on our side, so a level that moves with it can be told from one the product moved",
        "properties": {
         "runner": {
          "type": "string"
         },
         "model": {
          "type": [
           "string",
           "null"
          ]
         },
         "driver": {
          "type": [
           "integer",
           "null"
          ],
          "description": "The driver's version"
         },
         "signed": {
          "type": "boolean",
          "description": "Every request signed (Web Bot Auth)"
         },
         "inbox": {
          "type": [
           "array",
           "null"
          ],
          "items": {
           "type": "string"
          },
          "description": "The domains of the test inboxes it used"
         },
         "robots": {
          "enum": [
           "start",
           "obey",
           "skip",
           "consent"
          ],
          "description": "robots.txt on this drive: start (only the address driven), obey or skip (every page; account steps obey a rule for all user agents, or skip it), consent (the owner ordered the drive)"
         }
        }
       },
       "history": {
        "type": "array",
        "description": "The level per day, oldest first",
        "items": {
         "type": "object",
         "properties": {
          "run": {
           "type": "string"
          },
          "date": {
           "type": "string",
           "format": "date"
          },
          "level": {
           "$ref": "#/components/schemas/Level"
          },
          "why": {
           "enum": [
            "product",
            "rules",
            "noise"
           ],
           "description": "Why it moved from the entry before: product (a new drive gave another level), rules (a new set of rules moved it: rules_date), noise (the sign-up let our agent in on some drives and not others)"
          },
          "rules_date": {
           "type": "string",
           "format": "date"
          },
          "methodology": {
           "type": "integer"
          },
          "engine": {
           "type": "object",
           "description": "What made that drive on our side, as engine"
          }
         }
        }
       },
       "works_assisted": {
        "type": [
         "object",
         "null"
        ],
        "description": "The work line: what the agent did once a person set up the account or cleared a step at the door, from the newest drive that measured it. Shown next to every L1 and L2; never part of the level. null: not measured yet",
        "properties": {
         "core": {
          "type": [
           "string",
           "null"
          ],
          "description": "Core tasks done of all, as done/total",
          "example": "5/8"
         },
         "coverage_core": {
          "type": "integer"
         },
         "via": {
          "type": [
           "string",
           "null"
          ]
         },
         "run": {
          "type": "string"
         },
         "date": {
          "type": "string",
          "format": "date"
         }
        }
       },
       "nothing_to_pay": {
        "type": "boolean",
        "description": "The product has nothing to pay for: L5 says so in its own words"
       },
       "routes": {
        "type": "array",
        "description": "Every way in the product offers, tried agent-native first (since the rules of 12 Oct 2026; empty on older drives). A way not tried has its reason, ours, never the product's wall",
        "items": {
         "type": "object",
         "properties": {
          "route": {
           "type": "string",
           "example": "sso_github"
          },
          "offered": {
           "enum": [
            "documented",
            "seen",
            "listed",
            "no",
            "unknown"
           ]
          },
          "tried": {
           "type": "boolean"
          },
          "not_tried": {
           "type": [
            "string",
            "null"
           ],
           "enum": [
            "no_kit",
            "over_cap",
            "policy",
            "time",
            "same_as",
            "assisted_only",
            "idp_blocked",
            "sign_in_code",
            "robots",
            null
           ]
          },
          "result": {
           "type": [
            "string",
            "null"
           ],
           "enum": [
            "in",
            "partial",
            "walled",
            "refused",
            "broken",
            "not_reached",
            null
           ]
          },
          "wall": {
           "type": [
            "object",
            "null"
           ],
           "properties": {
            "type": {
             "type": [
              "string",
              "null"
             ]
            },
            "owner": {
             "enum": [
              "product",
              "idp",
              "platform",
              "ours",
              null
             ]
            }
           }
          },
          "person": {
           "type": [
            "string",
            "null"
           ],
           "enum": [
            "none",
            "once",
            "each",
            null
           ]
          },
          "brings": {
           "type": [
            "string",
            "null"
           ]
          },
          "fresh": {
           "type": [
            "boolean",
            "null"
           ]
          },
          "minutes": {
           "type": [
            "number",
            "null"
           ]
          }
         }
        }
       },
       "checkout": {
        "type": [
         "object",
         "null"
        ],
        "description": "The walk to the last click: how far the checkout went (reached: last_click, card_form, plan_page, no) and what it showed (processor, captcha, three_ds, card_form, phone_field, wallets, rail_offer, price, currency, period, plan, last_button)"
       },
       "docs": {
        "type": [
         "object",
         "null"
        ],
        "description": "The docs read and judged by our side before the drive: pages read and listed, sampled, and the verdict (overall: complete, gaps, thin, unreachable; getting_started, auth, errors, examples, freshness, newest, core_pages)"
       },
       "claims": {
        "type": [
         "object",
         "null"
        ],
        "description": "The claims ledger: each way the docs give to do the core work, tried once. claimed, tried, held, broken (documented but didn't work), not_tried, undocumented_works (worked but the docs don't describe it)",
        "properties": {
         "claimed": {
          "type": "integer"
         },
         "tried": {
          "type": "integer"
         },
         "held": {
          "type": "integer"
         },
         "broken": {
          "type": "integer"
         },
         "unclear": {
          "type": "integer",
          "description": "Ran, but the result wasn't read back"
         },
         "not_tried": {
          "type": "integer"
         },
         "undocumented_works": {
          "type": "integer"
         }
        }
       },
       "ladder": {
        "type": "object",
        "description": "The nine checkpoints, each with status and note, in the order of the agent's eight steps (Find → Learn → Sign up → Get a key → Do the work → Pay → Cancel → Leave; Find: none, it is the Agent-ready setup score; Learn: docs; Sign up: signup, verify; Get a key: credentials, first_call; Do the work: first_action; Pay: pay; Cancel: cancel; Leave: delete). pay: grade P0-P5 by how agentic paying is; from P3 up only with a payment our side proved (paid); a rail only seen has exercised false, its grade capped at P3 and the grade it would give in detected_grade"
       },
       "attempts": {
        "type": "array",
        "items": {
         "type": "object"
        }
       },
       "pay_options": {
        "type": [
         "object",
         "null"
        ],
        "description": "The pay checkpoint: the ways to pay it offers an agent (our pay probe before the drive, without paying; or an older drive's record), the payment our side proved, and what the owner could add so an agent pays on its own",
        "properties": {
         "checked": {
          "type": "string",
          "format": "date"
         },
         "source": {
          "enum": [
           "probe",
           "drive"
          ]
         },
         "options": {
          "type": "array",
          "description": "Agent ways first",
          "items": {
           "type": "object",
           "properties": {
            "id": {
             "type": "string",
             "example": "x402"
            },
            "name": {
             "type": "string"
            },
            "kind": {
             "enum": [
              "agent-rail",
              "agent-checkout",
              "mcp-tool",
              "billing",
              "checkout"
             ]
            },
            "first_party": {
             "type": "boolean",
             "description": "Answered on the vendor's own domain (or Stripe's own catalog)"
            },
            "lead": {
             "type": "boolean",
             "description": "Only a listing or a word in the docs, no answer from the vendor's own side"
            },
            "networks": {
             "type": "array",
             "items": {
              "type": "string"
             }
            },
            "testnet": {
             "type": "boolean"
            }
           }
          }
         },
         "agentic": {
          "type": "array",
          "items": {
           "type": "string"
          }
         },
         "paid": {
          "type": [
           "object",
           "null"
          ],
          "description": "The payment our side made and proved: a wallet transaction confirmed on chain (the trial card, a person's help, is never the agent paying)",
          "properties": {
           "rail": {
            "type": "string"
           },
           "network": {
            "type": [
             "string",
             "null"
            ],
            "example": "eip155:8453"
           },
           "testnet": {
            "type": "boolean"
           },
           "tx": {
            "type": [
             "string",
             "null"
            ]
           },
           "amount": {
            "type": [
             "number",
             "string",
             "null"
            ]
           },
           "currency": {
            "type": "string"
           },
           "at": {
            "type": [
             "string",
             "null"
            ]
           }
          }
         },
         "exercised": {
          "type": [
           "boolean",
           "null"
          ]
         },
         "detected_grade": {
          "type": [
           "string",
           "null"
          ]
         },
         "trial": {
          "type": "object",
          "properties": {
           "no_card": {
            "type": [
             "boolean",
             "null"
            ]
           },
           "card_required": {
            "type": [
             "boolean",
             "null"
            ]
           },
           "free_plan": {
            "type": [
             "boolean",
             "null"
            ]
           }
          }
         },
         "owner_fixes": {
          "type": "array",
          "items": {
           "type": "object",
           "properties": {
            "title": {
             "type": "string",
             "example": "Accept x402 or MPP on your API"
            },
            "how": {
             "type": "string"
            }
           }
          }
         }
        }
       },
       "who_gets_in": {
        "type": [
         "object",
         "null"
        ],
        "description": "Who gets in, next to the level and never part of it. server: our agent from our server (in, edge: stopped before the sign-up page, captcha: a CAPTCHA on the form, form: turned away at the form, robots: a robots.txt rule that names AI agents, closed). signed: the sign-up page opened by a signed agent Cloudflare knows, JavaScript off (page, check, block, robots, unknown), with the date. browser: an agent in a person's browser, from the kind of check (in, through, captcha, unknown), not measured. our_key: verified once Cloudflare knows our agent's key. robots: closed when robots.txt asks crawlers to stay off the sign-up page. tip: the edge stopped agents on a server and signed agents reached the page",
        "properties": {
         "server": {
          "type": "object",
          "properties": {
           "state": {
            "enum": [
             "in",
             "edge",
             "captcha",
             "form",
             "robots",
             "closed"
            ]
           }
          }
         },
         "signed": {
          "type": "object",
          "properties": {
           "state": {
            "enum": [
             "page",
             "check",
             "block",
             "robots",
             "unknown"
            ]
           },
           "kind": {
            "enum": [
             "signup",
             "home"
            ]
           },
           "at": {
            "type": "string",
            "format": "date"
           }
          }
         },
         "browser": {
          "type": "object",
          "properties": {
           "state": {
            "enum": [
             "in",
             "through",
             "captcha",
             "unknown"
            ]
           },
           "measured": {
            "type": "boolean"
           }
          }
         },
         "our_key": {
          "enum": [
           "verified",
           "pending"
          ]
         },
         "robots": {
          "enum": [
           "closed",
           null
          ],
          "description": "robots.txt asks crawlers to stay off the sign-up page"
         },
         "tip": {
          "type": "boolean"
         }
        }
       },
       "after_wall": {
        "type": [
         "object",
         "null"
        ],
        "description": "After the wall: what the agent did on its own once a person cleared one step at the door (a bot check, a phone code, a refused sign-up), set up the account, or gave a card for a free trial that asks for one. Never part of the level, which counts only what the agent did alone. null: no person helped",
        "properties": {
         "step": {
          "type": "string",
          "description": "The first checkpoint a person did"
         },
         "steps": {
          "type": "array",
          "items": {
           "type": "string"
          }
         },
         "via": {
          "type": "string",
          "description": "human handoff (in the agent's browser), human, own browser, human setup, owner access, human, trial card (a card a person gave for a free trial)"
         },
         "kind": {
          "type": [
           "string",
           "null"
          ],
          "enum": [
           "challenge",
           "browser-check",
           "phone",
           "card",
           "signup-refused",
           "other",
           null
          ]
         },
         "label": {
          "type": "string",
          "example": "measured after a human cleared sign-up"
         },
         "agent_steps": {
          "type": "array",
          "description": "Checkpoints after it the agent passed on its own",
          "items": {
           "type": "object",
           "properties": {
            "rung": {
             "type": "string"
            },
            "status": {
             "enum": [
              "headless",
              "browser"
             ]
            }
           }
          }
         },
         "done": {
          "type": "array",
          "description": "Capabilities the agent did and read back on its own once in",
          "items": {
           "type": "object",
           "properties": {
            "cap": {
             "type": "string"
            },
            "capability": {
             "type": "string"
            },
            "weight": {
             "type": "string"
            },
            "route": {
             "enum": [
              "headless",
              "browser"
             ]
            }
           }
          }
         },
         "coverage_core": {
          "type": [
           "integer",
           "null"
          ]
         },
         "parts": {
          "type": "array",
          "description": "The part scores measured after the wall: they carry the label",
          "items": {
           "enum": [
            "holds_up",
            "docs_match"
           ]
          }
         }
        }
       }
      }
     }
    ]
   },
   "Me": {
    "type": "object",
    "properties": {
     "user": {
      "$ref": "#/components/schemas/User"
     },
     "claims": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Claim"
      }
     },
     "orders": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Order"
      }
     },
     "monthly": {
      "type": "object",
      "description": "The Monthly drive for your next product: kept (how many you have), available (under 10), month_cents, year_cents",
      "properties": {
       "kept": {
        "type": "integer"
       },
       "available": {
        "type": "boolean"
       },
       "month_cents": {
        "type": "integer"
       },
       "year_cents": {
        "type": "integer"
       }
      }
     }
    }
   }
  }
 }
}