{
  "components": {
    "schemas": {
      "Callable": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Listing"
          },
          {
            "properties": {
              "agentNotes": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "authNotes": {
                "type": "string"
              },
              "connect": {
                "description": "the record's connect snippets: claudeCode, config, http, install, headless, x402",
                "type": "object"
              },
              "docs": {
                "type": "string"
              },
              "x402Endpoints": {
                "items": {
                  "properties": {
                    "network": {
                      "type": "string"
                    },
                    "priceUsd": {
                      "type": "number"
                    },
                    "url": {
                      "type": "string"
                    }
                  },
                  "type": "object"
                },
                "type": "array"
              }
            },
            "type": "object"
          }
        ]
      },
      "Error": {
        "properties": {
          "detail": {
            "type": "string"
          },
          "error": {
            "type": "string"
          },
          "param": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "Listing": {
        "properties": {
          "auth": {
            "type": "string"
          },
          "capabilities": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "endpoint": {
            "type": "string"
          },
          "grade": {
            "enum": [
              "AA",
              "A",
              "BB",
              "B",
              "C",
              "D",
              "E",
              "F"
            ],
            "type": "string"
          },
          "jobPrice": {
            "properties": {
              "label": {
                "type": "string"
              },
              "unit": {
                "type": "string"
              },
              "usd": {
                "type": "number"
              }
            },
            "type": "object"
          },
          "json": {
            "type": "string"
          },
          "keyless": {
            "type": "boolean"
          },
          "keylessBy": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "leadPriceUsd": {
            "description": "the lowest published price for anything the listing sells, in any unit: for the max filter and the headline, never the rule's price step",
            "type": "number"
          },
          "leadUnit": {
            "type": "string"
          },
          "letme": {
            "type": "string"
          },
          "markdown": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "p95ms": {
            "type": "number"
          },
          "priceSummary": {
            "type": "string"
          },
          "pricing": {
            "type": "string"
          },
          "rank": {
            "type": "integer"
          },
          "ruledOutBy": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "sample": {
            "description": "a preview sample, not a measurement",
            "type": "boolean"
          },
          "score": {
            "type": "number"
          },
          "slug": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "vendor": {
            "type": "string"
          },
          "where": {
            "type": "string"
          },
          "x402": {
            "enum": [
              "yes",
              "partial",
              "no"
            ],
            "type": "string"
          }
        },
        "type": "object"
      },
      "NotFound": {
        "properties": {
          "detail": {
            "type": "string"
          },
          "error": {
            "type": "string"
          },
          "job": {
            "type": "string"
          },
          "search": {
            "type": "string"
          },
          "suggestions": {
            "items": {
              "properties": {
                "capability": {
                  "type": "string"
                },
                "letme": {
                  "type": "string"
                },
                "pick": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          },
          "words": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "Pick": {
        "properties": {
          "alternatives": {
            "description": "the next n in the rule's order",
            "items": {
              "$ref": "#/components/schemas/Listing"
            },
            "type": "array"
          },
          "calling": {
            "properties": {
              "note": {
                "type": "string"
              },
              "open": {
                "type": "boolean"
              }
            },
            "type": "object"
          },
          "capability": {
            "type": "string"
          },
          "directory": {
            "properties": {
              "base": {
                "type": "string"
              },
              "build": {
                "type": "string"
              },
              "fetchedAt": {
                "format": "date-time",
                "type": "string"
              },
              "note": {
                "type": "string"
              },
              "preview": {
                "type": "boolean"
              },
              "stale": {
                "type": "boolean"
              }
            },
            "type": "object"
          },
          "filters": {
            "description": "the filters applied, and n",
            "type": "object"
          },
          "job": {
            "type": "string"
          },
          "letme": {
            "description": "this answer's letme URL",
            "type": "string"
          },
          "live": {
            "description": "whether letme calls tools; false, letme picks and the agent calls the pick",
            "type": "boolean"
          },
          "nearest": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Listing"
              }
            ],
            "description": "when pick is null: the best listing without the filters, with ruledOutBy"
          },
          "order": {
            "type": "string"
          },
          "pick": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Callable"
              },
              {
                "type": "null"
              }
            ],
            "description": "null when no listing fits the filters"
          },
          "picking": {
            "type": "boolean"
          },
          "priceUnit": {
            "properties": {
              "label": {
                "type": "string"
              },
              "unit": {
                "description": "a unit key, as unitPrices in the directory's tools.json use it (1k-requests, audio-minute, 1m-chars)",
                "type": "string"
              }
            },
            "type": "object"
          },
          "rule": {
            "type": "string"
          },
          "ruleSays": {
            "type": "string"
          },
          "tool": {
            "$ref": "#/components/schemas/Callable"
          },
          "topFor": {
            "description": "for a slug: the capabilities letme picks this listing for",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "understood": {
            "$ref": "#/components/schemas/Understood"
          },
          "why": {
            "description": "one sentence, in the rule's terms: the step that decided. A price step names the unit it compared in (cheaper per 1,000 requests than X); when price didn't decide it says so, and the step that did (p95, then the Anchor score, then the name)",
            "type": "string"
          }
        },
        "type": "object"
      },
      "Understood": {
        "properties": {
          "capability": {
            "type": "string"
          },
          "confidence": {
            "enum": [
              "high",
              "medium",
              "low"
            ],
            "type": "string"
          },
          "job": {
            "type": "string"
          },
          "matched": {
            "items": {
              "properties": {
                "via": {
                  "type": "string"
                },
                "weight": {
                  "type": "number"
                },
                "word": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          },
          "named": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Callable"
              }
            ],
            "description": "a listing the job names (search with exa), with carries and fits"
          },
          "others": {
            "description": "up to three other capabilities when the margin is small, with their own picks",
            "items": {
              "properties": {
                "capability": {
                  "type": "string"
                },
                "letme": {
                  "type": "string"
                },
                "pick": {
                  "type": "object"
                },
                "score": {
                  "type": "number"
                }
              },
              "type": "object"
            },
            "type": "array"
          },
          "score": {
            "type": "number"
          },
          "words": {
            "type": "string"
          }
        },
        "type": "object"
      }
    }
  },
  "info": {
    "contact": {
      "email": "agents@anchorterminal.com",
      "name": "Anchor Terminal Ltd",
      "url": "https://www.anchorterminal.com/letme/"
    },
    "description": "letme picks: by a listing's slug, a capability id or a job in words, with filters, it answers with the listing the published rule picks (highest Anchor grade for the capability, then price, compared only between prices whose item names the job, in one unit (the unit most listings at that grade price the job in, usage before plans), then p95 latency, then the Anchor score, then the name), how to call it direct, why it won and the alternatives. Price is compared only between prices whose item names the job (an item named Search for web.search, never Fetch) in one unit per grade (priceUnit), never a credit against a request; a listing with no such price sorts after those with one. jobPrice on each listing is the price the rule read, and leadPriceUsd the lowest price for anything, which the rule never reads. why names the step that decided. Calling through letme (one key, payments) comes later; nothing here calls a tool. The ratings are the directory's public files (https://www.anchorterminal.com/api/v1/tools.json, /api/v1/capabilities.json, /api/v1/categories.json). How words map to capabilities is published at https://letme.dev/words.json. JSON by default, Markdown with Accept: text/markdown or a .md suffix. No key, no account, CORS *. Limits: 20 requests a second per IP address, with bursts of up to 40; over that, 429 with Retry-After. Status: https://letme.dev/status, with uptime by day and every outage at https://www.anchorterminal.com/status/.",
    "summary": "The best tool for a job, by Anchor Terminal's published grades, and how to call it direct.",
    "termsOfService": "https://www.anchorterminal.com/letme/",
    "title": "letme",
    "version": "2026.10.04-1801"
  },
  "openapi": "3.1.0",
  "paths": {
    "/": {
      "get": {
        "description": "With q (or job, task, capability): the same answer as /{target} for that text. Without: the index, Markdown by default.",
        "operationId": "pickByQuery",
        "parameters": [
          {
            "description": "The job in words, a capability id or a slug",
            "example": "transcribe a phone call",
            "in": "query",
            "name": "q",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Where it runs, comma-separated, as the record says: hosted, local, both, library, spec",
            "example": "hosted,both",
            "in": "query",
            "name": "where",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Kinds, comma-separated: mcp, http-api, sdk, model, router, platform, framework, protocol",
            "example": "mcp,http-api",
            "in": "query",
            "name": "kind",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The record's auth, comma-separated: none, api-key (or apikey), oauth, pat, mixed",
            "example": "none,api-key",
            "in": "query",
            "name": "auth",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1 for listings usable with no key of your own: auth none, an x402 route, or anonymous use the record describes",
            "example": "1",
            "in": "query",
            "name": "keyless",
            "schema": {
              "enum": [
                "1",
                "0",
                "true",
                "false",
                "yes",
                "no"
              ],
              "type": "string"
            }
          },
          {
            "description": "yes for listings that take x402 payments (the record's level isn't no)",
            "example": "yes",
            "in": "query",
            "name": "x402",
            "schema": {
              "enum": [
                "yes",
                "no"
              ],
              "type": "string"
            }
          },
          {
            "description": "Pricing models, comma-separated: free, freemium, usage, paid, byo-plan",
            "example": "free,freemium",
            "in": "query",
            "name": "pricing",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The lead unit price in dollars at most this; a listing with no published price is out",
            "example": 0.01,
            "in": "query",
            "name": "max",
            "schema": {
              "type": "number"
            }
          },
          {
            "description": "This grade or better",
            "example": "BB",
            "in": "query",
            "name": "minGrade",
            "schema": {
              "enum": [
                "AA",
                "A",
                "BB",
                "B",
                "C",
                "D",
                "E",
                "F"
              ],
              "type": "string"
            }
          },
          {
            "description": "Slugs to leave out, comma-separated, to fall back after a failure",
            "example": "exa-mcp",
            "in": "query",
            "name": "not",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "How many alternatives, 0 to 10 (default 3)",
            "example": 3,
            "in": "query",
            "name": "n",
            "schema": {
              "maximum": 10,
              "minimum": 0,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pick"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "The pick, or the index"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "A filter letme can't read; param names it"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFound"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "No capability matches the words; suggestions and the directory's search"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Over the limit (20 requests a second per IP address, with bursts of up to 40); Retry-After says how many seconds to wait. error is rate_limited"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "letme is restarting or loading the ratings; Retry-After says when to try again"
          }
        },
        "summary": "The pick for a job given as a query, or the index without one"
      },
      "post": {
        "description": "For long descriptions, or clients that prefer POST. The body's fields are the job and the same filters as the query parameters. POST anywhere else is 405: letme doesn't call tools yet.",
        "operationId": "pickByBody",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "example": {
                  "job": "send an sms",
                  "keyless": true,
                  "n": 3
                },
                "properties": {
                  "auth": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "job": {
                    "description": "The job in words, a capability id or a listing's slug (q, task and capability are read as job too)",
                    "type": "string"
                  },
                  "keyless": {
                    "type": "boolean"
                  },
                  "kind": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "max": {
                    "type": "number"
                  },
                  "minGrade": {
                    "enum": [
                      "AA",
                      "A",
                      "BB",
                      "B",
                      "C",
                      "D",
                      "E",
                      "F"
                    ],
                    "type": "string"
                  },
                  "n": {
                    "type": "integer"
                  },
                  "not": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "pricing": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "where": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "x402": {
                    "type": "string"
                  }
                },
                "required": [
                  "job"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pick"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "The pick"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "A filter letme can't read; param names it"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFound"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "No capability matches the words"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Over the limit (20 requests a second per IP address, with bursts of up to 40); Retry-After says how many seconds to wait. error is rate_limited"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "letme is restarting or loading the ratings; Retry-After says when to try again"
          }
        },
        "summary": "The pick for a job given in a JSON body"
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "index",
        "responses": {
          "200": {
            "description": "Markdown"
          }
        },
        "summary": "The index, as Markdown"
      }
    },
    "/mcp": {
      "post": {
        "operationId": "mcp",
        "responses": {
          "200": {
            "description": "JSON-RPC"
          }
        },
        "summary": "The same answers over MCP (Streamable HTTP; tools: pick, about)"
      }
    },
    "/status": {
      "get": {
        "operationId": "status",
        "responses": {
          "200": {
            "description": "JSON, or Markdown with Accept: text/markdown or /status.md"
          },
          "503": {
            "description": "starting, with Retry-After"
          }
        },
        "summary": "letme.dev right now: ok, degraded or starting, the age of the ratings it picks from, its own check of the picks, uptime since start and the limits; the history is at the directory's /status/"
      }
    },
    "/words.json": {
      "get": {
        "operationId": "words",
        "responses": {
          "200": {
            "description": "JSON"
          }
        },
        "summary": "How a job's words map to capabilities: the steps, the weights and the table"
      }
    },
    "/{target}": {
      "get": {
        "description": "target is read as a listing's slug first (exa-mcp: that listing and how to call it, with topFor), then a capability id (web.search: the pick under the filters), then a job in words (send-an-sms, transcribe%20a%20phone%20call: hyphens, underscores, + and %20 read as spaces; the answer adds understood). A .md or .json suffix picks the format.",
        "operationId": "pick",
        "parameters": [
          {
            "description": "A slug, a capability id or a job in words",
            "example": "send-an-sms",
            "in": "path",
            "name": "target",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Where it runs, comma-separated, as the record says: hosted, local, both, library, spec",
            "example": "hosted,both",
            "in": "query",
            "name": "where",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Kinds, comma-separated: mcp, http-api, sdk, model, router, platform, framework, protocol",
            "example": "mcp,http-api",
            "in": "query",
            "name": "kind",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The record's auth, comma-separated: none, api-key (or apikey), oauth, pat, mixed",
            "example": "none,api-key",
            "in": "query",
            "name": "auth",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "1 for listings usable with no key of your own: auth none, an x402 route, or anonymous use the record describes",
            "example": "1",
            "in": "query",
            "name": "keyless",
            "schema": {
              "enum": [
                "1",
                "0",
                "true",
                "false",
                "yes",
                "no"
              ],
              "type": "string"
            }
          },
          {
            "description": "yes for listings that take x402 payments (the record's level isn't no)",
            "example": "yes",
            "in": "query",
            "name": "x402",
            "schema": {
              "enum": [
                "yes",
                "no"
              ],
              "type": "string"
            }
          },
          {
            "description": "Pricing models, comma-separated: free, freemium, usage, paid, byo-plan",
            "example": "free,freemium",
            "in": "query",
            "name": "pricing",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "The lead unit price in dollars at most this; a listing with no published price is out",
            "example": 0.01,
            "in": "query",
            "name": "max",
            "schema": {
              "type": "number"
            }
          },
          {
            "description": "This grade or better",
            "example": "BB",
            "in": "query",
            "name": "minGrade",
            "schema": {
              "enum": [
                "AA",
                "A",
                "BB",
                "B",
                "C",
                "D",
                "E",
                "F"
              ],
              "type": "string"
            }
          },
          {
            "description": "Slugs to leave out, comma-separated, to fall back after a failure",
            "example": "exa-mcp",
            "in": "query",
            "name": "not",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "How many alternatives, 0 to 10 (default 3)",
            "example": 3,
            "in": "query",
            "name": "n",
            "schema": {
              "maximum": 10,
              "minimum": 0,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pick"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "The listing or the pick"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "A filter letme can't read; param names it"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFound"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Nothing by that name and no capability matches the words"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "Over the limit (20 requests a second per IP address, with bursts of up to 40); Retry-After says how many seconds to wait. error is rate_limited"
          },
          "503": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "letme is restarting or loading the ratings; Retry-After says when to try again"
          }
        },
        "summary": "A listing, the best listing for a capability, or the best listing for a job in words"
      }
    }
  },
  "servers": [
    {
      "url": "https://letme.dev"
    }
  ]
}
