---
title: "One drive with its evidence: the level, the five outcomes, the part scores, every checkpoint and every attempt"
method: GET
path: "/api/tools/{slug}.json"
tags: ["Directory"]
---

# One drive with its evidence: the level, the five outcomes, the part scores, every checkpoint and every attempt

`GET /api/tools/{slug}.json`

## Request

- Base URL: `https://agentdrives.com`
- URL: `https://agentdrives.com/api/tools/{slug}.json`
- Auth: none required

## Path parameters

- `slug` string, required

## Response `200`

Drive

- Tool: One product in /api/tools.json (the same fields open each /api/tools/{slug}.json)
  - `id` string: The product's stable id: never reused, kept when its slug or address changes. Resolve it at /api/id/{id}
  - `slug` string: The product's address in the directory (can change; id doesn't)
  - `name` string
  - `domain` string
  - `icon` string, nullable: The product's logo, a path on this site
  - `category` string: The category id
  - `category_name` string
  - `tested_at` string, date: The day of the drive behind the level
  - `url` string, uri: The product's page here
  - `json` string, uri: Its full record: /api/tools/{slug}.json
  - `draft` boolean: Not reviewed yet: the result may still change
  - `origin` 'editorial' | 'owner': editorial: we picked the product; owner: its owner ordered the drive
  - `disclosure` string: Only on a drive its owner paid for: the label to show with it
  - `stale` boolean: The newest drive is older than 182 days
  - `level_selfhost` integer, nullable: The level of the self-hosted edition, when it was driven (null: not driven)
  - `summary` string: What an agent can do with it, in a sentence or two
  - `first_blocker` string: The first thing that stops or slows an agent
  - `coverage_source` 'computed' | 'reported': computed: work done measured against the product's capability map; reported: counted by the driving agent
  - `core` string, nullable: Core features done of all, as done/total
  - `pay` string, nullable: The pay grade, P0 to P5 (n/a: nothing to pay for)
  - `lets_agent` string, nullable: A bot check that let our signed agent through (null: none seen)
  - `mcp` 'official' | 'third-party' | 'docs' | 'none' | 'null', nullable: Whether it has an MCP server: its own, someone else's, only one that searches its docs (docs), or none; null when not checked
  - `level` integer: 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)
  - `level_name` string
  - `parts` Parts: The part scores (methodology 21), 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.
    - `holds_up` integer, nullable: Reliability and the crash test. null until the crash test ran
    - `docs_match` integer, nullable: The docs checked against live behaviour (accuracy and completeness). null until the full surface audit ran
    - `setup` integer, nullable: 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` 'private' | 'null', nullable: Security is reported privately to the owner, the same for every product: no score or count. private when a security review ran on the drive, null before one did
    - `standards` object[]: Whether the product speaks the current version of each standard, as facts, never points
      - `standard` string
      - `state` 'current' | 'behind'
      - `behind` integer, nullable: Revisions behind, when countable
      - `value` string, nullable
  - `stages` Stage[]
    - `key` 'in' | 'work' | 'pay' | 'leave'
    - `label` string
    - `state` 'yes' | 'part' | 'no' | 'unreached' | 'na'
    - `text` string
    - `value` 'paid' | 'partial' | 'ready' | 'checkout' | 'person' | 'not_tried' | 'unreached' | 'nothing': Pay only: paid (a payment we made and checked that pays for the work: credits or a plan for its account, or per call for at least 80% of the core; over x402 or MPP, or one purchase at the checkout on the owner's order with their code; it counts for 90 days), partial (it pays per call, for less of the core than that), ready (ready to pay, payment not yet proven: a valid HTTP 402 offer on a core task that our wallet could meet, or the checkout filled up to the pay button with no person in the way; never L5), checkout (the agent reached the checkout, the last step before the money, without that proof, 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` object: 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)
      - `caps` string[]
      - `core` integer
      - `share` integer, nullable
    - `left` 'deleted' | 'data_only' | 'nothing_made' | 'removed' | 'expires' | 'stuck' | 'wallet_kept': 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
    - `delete` object, nullable: Leave only: the delete as its own fact beside Leave (Leave says whether it stops paying on its own). state yes: what it made goes (its account deleted, or removed, or gone by itself); part: its data deleted, the login stays; no: it stays; na: nothing made; unreached. text in words, why: the drive's note at delete
      - `state` 'yes' | 'part' | 'no' | 'na' | 'unreached'
      - `text` string
      - `why` string, nullable
    - `after_hours` number: Leave only, with expires: after how long the product removes what the agent made, per its docs
    - `route` 'agent_rail' | 'projects' | 'billing_api' | 'agent_checkout' | 'card_checkout' | 'portal' | 'sales' | 'none': Pays only: the most agentic way to buy the product offers
    - `why` string: 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` string: 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)
  - `next` object
    - `to` integer, nullable
    - `text` string
  - `outcomes` Outcome[]: The five outcomes: find, access, use, pay, leave
    - `key` 'find' | 'access' | 'use' | 'pay' | 'leave'
    - `label` string
    - `state` 'yes' | 'part' | 'no' | 'unreached' | 'na'
    - `text` string
    - `value` 'paid' | 'partial' | 'ready' | 'checkout' | 'person' | 'not_tried' | 'unreached' | 'nothing': Pay only: paid (a payment we made and checked that pays for the work: credits or a plan for its account, or per call for at least 80% of the core; over x402 or MPP, or one purchase at the checkout on the owner's order with their code; it counts for 90 days), partial (it pays per call, for less of the core than that), ready (ready to pay, payment not yet proven: a valid HTTP 402 offer on a core task that our wallet could meet, or the checkout filled up to the pay button with no person in the way; never L5), checkout (the agent reached the checkout, the last step before the money, without that proof, 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` object: 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)
      - `caps` string[]
      - `core` integer
      - `share` integer, nullable
    - `left` 'deleted' | 'data_only' | 'nothing_made' | 'removed' | 'expires' | 'stuck' | 'wallet_kept': 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
    - `delete` object, nullable: Leave only: the delete as its own fact, as on its stage (Stage.delete)
    - `after_hours` number: Leave only, with expires: after how long the product removes what the agent made, per its docs
    - `route` 'agent_rail' | 'projects' | 'billing_api' | 'agent_checkout' | 'card_checkout' | 'portal' | 'sales' | 'none': Pays only: the most agentic way to buy the product offers
    - `why` string: 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` string: 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` 'in' | 'work' | 'pay' | 'leave'
    - `have` string[]: Find only: what the drive found
    - `docs` string: Find only: the docs pass's verdict, when the drive read the docs
  - `access` Access[]: How an agent gets in
    - `key` 'keyless' | 'local' | 'try_first' | 'no_account' | 'pay_per_call' | 'key_by_api' | 'mcp_signin' | 'email_signup' | 'browser_signup' | 'by_name' | 'person'
    - `label` string
    - `routes` string[]: The route ids behind it (e.g. pay_per_call, email_code, sso_github)
    - `minutes` number, nullable: Minutes to the first call on this way
    - `core` string, nullable: Core tasks done on this way, as done/total
  - `minutes` number, nullable: Minutes to the first call on the fastest way in; within a level, the order after work done
  - `stop` string, nullable: 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` integer, nullable: Work done: the share of the core features done and read back, through documented routes (null: not measured)
  - `entry` 'self-start' | 'setup' | 'closed': 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` string[]: agent-can-buy: an agent paid through an agent-native rail, proven from our side; agent-can-leave: leaves on its own
  - `pays_with` string[]: 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` boolean: Our side made and proved a payment on one of them (the transaction is in the tool's pay_options.paid)
  - `blocks_agent` string, nullable: 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` unknown
  - `monitored` boolean: Driven monthly
  - `freshness` 'fresh' | 'aging' | 'redrive': How old the listed drive is: aging from 90 days (Driven over 3 months ago), redrive from 180 (Needs a new drive)
  - `newer_drives` object, nullable: Finished drives after the listed one, not listed yet: how many and the newest's date. null: the listed drive is the newest
    - `count` integer
    - `newest` string, date
  - `same_level_drives` integer: The latest drives in a row that gave this level
  - `drives` integer: Every drive of the product so far
  - `robots` Robots, nullable: 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
    - `rule` 'named' | 'star'
    - `step` 'signup' | 'verify' | 'credentials' | 'first_call' | 'null', nullable
    - `seen` string, date: The newest drive that met it
    - `held` boolean
  - `ways_in` string[]: 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` 'complete' | 'gaps' | 'thin' | 'unreachable' | 'null', nullable: The docs pass's verdict (null: no docs pass on that drive)
  - `ids` ToolIds: What the product joins on: its company's and surfaces' stable ids, its slugs and domain, and outside ids
    - `org` string, nullable: The company's stable id (org_…), by its registrable domain
    - `surfaces` object: A stable id (srf_…) per way to use it: web, api, mcp, cli, sdk
    - `slugs` string[]: Every slug it has had
    - `domain` string, nullable
    - `wikidata` string: Its Wikidata item (QID), where its official website matches
    - `mcp_registry` string[]: Its servers' names in the official MCP registry
  - `scores` object: The measures behind the parts: coverage, reliability, resilience, setup, and after the full surface audit surface_coverage, docs_accuracy, docs_completeness
  - `methodology` integer: The scoring rules that made this result
  - `rules_date` string, date: The date of those rules, as pages name them ("Rules of ..."; now 2026-10-19). Every set of rules: /method/changelog
  - `engine` object, nullable: What made this drive on our side, so a level that moves with it can be told from one the product moved
    - `runner` string
    - `model` string, nullable
    - `driver` integer, nullable: The driver's version
    - `signed` boolean: Every request signed (Web Bot Auth)
    - `inbox` string[], nullable: The domains of the test inboxes it used
    - `robots` 'start' | 'obey' | 'skip' | 'consent': 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` object[]: The level per day, oldest first
    - `run` string
    - `date` string, date
    - `level` integer: 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)
    - `why` 'product' | 'rules' | 'noise' | 'agent': 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), agent (our agent changed between the two drives: another version of it)
    - `rules_date` string, date
    - `methodology` integer
    - `engine` object: What made that drive on our side, as engine
  - `works_assisted` object, nullable: 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
    - `core` string, nullable: Core tasks done of all, as done/total
    - `coverage_core` integer
    - `via` string, nullable
    - `run` string
    - `date` string, date
  - `nothing_to_pay` boolean: The product has nothing to pay for: L5 says so in its own words
  - `routes` object[]: 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
    - `route` string
    - `offered` 'documented' | 'seen' | 'listed' | 'no' | 'unknown'
    - `tried` boolean
    - `not_tried` 'no_kit' | 'over_cap' | 'policy' | 'time' | 'same_as' | 'assisted_only' | 'idp_blocked' | 'sign_in_code' | 'robots' | 'null', nullable
    - `result` 'in' | 'partial' | 'walled' | 'refused' | 'broken' | 'not_reached' | 'not_counted' | 'null', nullable: not_counted: in only with our own Google or GitHub account, which drives no longer use
    - `wall` object, nullable
      - `type` string, nullable
      - `owner` unknown
    - `person` 'none' | 'once' | 'each' | 'null', nullable
    - `brings` string, nullable
    - `fresh` boolean, nullable
    - `minutes` number, nullable
  - `checkout` object, nullable: 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` object, nullable: 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` object, nullable: 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)
    - `claimed` integer
    - `tried` integer
    - `held` integer
    - `broken` integer
    - `unclear` integer: Ran, but the result wasn't read back
    - `not_tried` integer
    - `undocumented_works` integer
  - `ladder` object: 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` object[]
  - `pay_options` object, nullable: 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
    - `checked` string, date
    - `source` 'probe' | 'drive'
    - `options` object[]: Agent ways first
      - `id` string
      - `name` string
      - `kind` 'agent-rail' | 'agent-checkout' | 'mcp-tool' | 'billing' | 'checkout'
      - `first_party` boolean: Answered on the vendor's own domain (or Stripe's own catalog)
      - `lead` boolean: Only a listing or a word in the docs, no answer from the vendor's own side
      - `networks` string[]
      - `testnet` boolean
    - `agentic` string[]
    - `paid` object, nullable: 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)
      - `rail` string
      - `network` string, nullable
      - `testnet` boolean
      - `tx` string, nullable
      - `amount` union
        - number
        - string
      - `currency` string
      - `at` string, nullable
    - `exercised` boolean, nullable
    - `detected_grade` string, nullable
    - `trial` object
      - `no_card` boolean, nullable
      - `card_required` boolean, nullable
      - `free_plan` boolean, nullable
    - `owner_fixes` object[]
      - `title` string
      - `how` string
  - `who_gets_in` object, nullable: 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
    - `server` object
      - `state` 'in' | 'edge' | 'captcha' | 'form' | 'robots' | 'closed'
    - `signed` object
      - `state` 'page' | 'check' | 'block' | 'robots' | 'unknown'
      - `kind` 'signup' | 'home'
      - `at` string, date
    - `browser` object
      - `state` 'in' | 'through' | 'captcha' | 'unknown'
      - `measured` boolean
    - `our_key` 'verified' | 'pending'
    - `robots` unknown
    - `tip` boolean
  - `after_wall` object, nullable: 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
    - `step` string: The first checkpoint a person did
    - `steps` string[]
    - `via` string: 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` 'challenge' | 'browser-check' | 'phone' | 'card' | 'signup-refused' | 'other' | 'null', nullable
    - `label` string
    - `agent_steps` object[]: Checkpoints after it the agent passed on its own
      - `rung` string
      - `status` 'headless' | 'browser'
    - `done` object[]: Capabilities the agent did and read back on its own once in
      - `cap` string
      - `capability` string
      - `weight` string
      - `route` 'headless' | 'browser'
    - `coverage_core` integer, nullable
    - `parts` string[]: The part scores measured after the wall: they carry the label

## Other responses

- `404`: not_found: no product with that slug; /api/tools.json lists every slug

## Changes

- **2026-10-19** `875c17f6ee52`: 2 info
  - added the optional property `allOf[#/components/schemas/ToolSummary]/outcomes/items/delete` to the response with the `200` status
  - added the optional property `allOf[#/components/schemas/ToolSummary]/stages/items/delete` to the response with the `200` status
- **2026-10-19** `b9957601c4c5`: 2 warning, 1 info
  - added the new `agent` enum value to the `allOf[subschema #2]/history/items/why` response property for the response status `200`
  - added the new `not_counted` enum value to the `allOf[subschema #2]/routes/items/result` response property for the response status `200`
  - added the optional property `allOf[#/components/schemas/ToolSummary]/newer_drives` to the response with the `200` status

[Operation history](https://skmtc.dev/agentdrives/apis/agentdrives-api/changes/api/tools/:slug.json/get.md)

---

[API](https://skmtc.dev/agentdrives/apis/agentdrives-api.md) · [All operations](https://skmtc.dev/agentdrives/apis/agentdrives-api/llms.txt) · [OpenAPI document](https://skmtc.dev/agentdrives/apis/agentdrives-api/revisions/94dcaabff4b2?raw)
