# Suffect, the whole site Every page of https://suffect.com as Markdown, then the agent skill. Each page's own twin is at its path plus `.md`. # Let your AI agent sign up for any API. Private alpha opening soon You approve once. Suffect creates the account in your name, caps the spend, and hands your agent a key that expires. - [Get early access](/#early-access) - [See how it works](/#how) ## How it works 1. **Your agent asks** When a vendor like ElevenLabs requires an account, a key or a subscription, your agent makes one call to Suffect: `request_access`, or `suffect request` from a terminal. 2. **You approve once** Your agent wants an account at ElevenLabs. One sheet shows the terms and the budget; you agree and sign up with your passkey. 3. **It gets a key that expires** Granted: a base URL and a token through Suffect's proxy, inside the budget. The ElevenLabs key stays in a vault. ## Built for the agents you already run One server, one skill and one command line: whichever your agent speaks, it can ask Suffect for access. - **MCP server**: for any MCP client, with OAuth sign-in - **Agent skill**: one SKILL.md that triggers on 401, 402 and 403 - **CLI**: `suffect request` from any terminal Runtimes: Claude Code, Codex, Cursor, Gemini CLI, OpenClaw. ## Access for your agent. Control for you. ### One key for every API Search with Exa, voice with ElevenLabs, video with Higgsfield, scraping with Firecrawl, inference with fal.ai: one credential and one price list for your agent. Every account is yours. ### Spend capped by your budget Calls Suffect can price are priced first and refused past the budget you set: a search inside the cap runs, a batch job past it is refused before anything is spent. ### The key never reaches your agent Your agent holds a proxied URL; the vendor key stays in the vault. ### A signed record of every approval The consent record names the provider, its terms by version and hash, and the budget, signed by your passkey and countersigned by Suffect. [The record, field by field](/spec#record) ### Never fights bot defenses Every signup request carries a signature. A CAPTCHA is handed to you, never solved for you. [For site operators](/bot) ### Revoke any time An approval stays active until you turn it off. Turn off Higgsfield and its key is revoked at once, while ElevenLabs keeps working. ## For agents, and the APIs they call ### For agents: Start with request_access. Install the skill or point any MCP client at Suffect. When a vendor answers 401, 402 or 403, your agent asks Suffect instead of asking you for a key. ```text request_access { "provider": "elevenlabs.io", "budget": { "amount": 20, "currency": "USD", "period": "month" } } // pending_consent: one sheet goes to your human // once they approve get_grant { "request_id": "req_01K8QX3M7T…" } // granted: a proxied base URL and a token that expires // https://proxy.suffect.com/v/elevenlabs.io ``` [Agent docs](/agents) ### For API vendors: Agent-originated customers, with a human who agreed. Publish one file at `/.well-known/suffect.json` and every agent signup becomes a signed, one-call account in a real human's name. ```json { "suffect": "0.2", "provider": { "name": "Example API", "domain": "example.com" }, "terms": [{ "kind": "terms_of_use", "url": "https://example.com/terms", "version": "2026-06-01", "sha256": "9f3c0a7e5b1d4c2a8e6f0b3d7c9a1e5f2b4d6c8a0e1f3b5d7c9a2e4f6b8d0c1e" }], "signup": { "level": 3, "endpoint": "https://api.example.com/suffect/signups" } } ``` [Vendor docs](/vendors) ## Questions ### Can I use it today? Not yet. As of 2026-10-20, the loop runs end to end against test vendors; the production service is not live, and no vendor account has been created for anyone. The private alpha opens soon. ### Will vendors block this? Some may. Suffect never evades a defense: every signup request is signed and identified, a challenge goes to you, and a vendor that publishes a manifest turns these signups into one signed call. Blocking costs a vendor a customer; a manifest wins one. ### Is this a password manager for agents? No. A password manager stores what you already created. Suffect creates the relationship, records your consent, caps the spend and keeps the key out of the agent. ### Is an agent clicking accept binding? UETA and E-SIGN bind the human an electronic agent acts for, and the signed record is the evidence that you approved. No court has ruled on the question yet. ### What does it cost? Nothing during the alpha. Developers will pay for Suffect afterwards. Suffect adds no markup to a vendor's price: the price on the sheet is the vendor's own. ## Get early access The private alpha opens soon for a small group of developers and API vendors. Write to hello@suffect.com with what your agent needs, or the API you run. - [Email Suffect](mailto:hello@suffect.com?subject=Early%20access) - [Follow on GitHub](https://github.com/suffect-dev) --- Canonical: https://suffect.com/. Every page of this site has a Markdown twin at the same path plus `.md`; the index is https://suffect.com/llms.txt. # For agents A vendor wants an account, a key or a subscription. Ask Suffect instead of asking your human for a key: they approve once, on one sheet, and you get a grant. - [The skill, as a file](/skill.md) - [The index for agents](/llms.txt) ## When to ask - A vendor API answers 401, 403 with an insufficient-scope message, or 402. - A vendor's documentation says "get an API key", "create an account" or "subscribe". - The task needs a capability no connected vendor provides; `search_catalog` finds one, with its price before the call when the catalog knows it. ## The one call Over MCP. Without MCP: `suffect request elevenlabs.io --budget 20/mo --json`, with your access token in `SUFFECT_TOKEN`. ```json request_access { "provider": "elevenlabs.io", "budget": { "amount": 20, "currency": "USD", "period": "month" } } ``` When a catalog row's terms carry `automated_signup_restricted` or `signup_on_behalf_restricted`, the vendor's terms restrict what you are about to ask for: tell the human in one sentence before you ask. The sheet shows the clause, their approval acknowledges it, and Suffect proceeds openly as their identified agent. ## What comes back - **granted**: call `get_grant` with the `request_id` (or run `suffect env `) and use the base URL and token it returns: point the vendor's SDK at the base URL and send the token as the bearer credential. - **pending_consent**: tell the human in one sentence what you asked for and give them the `consent_url`. Wait, then check with `get_grant`. - **provisioning**: approved; the account is being created. Check again with `get_grant` in a minute. - **pending_takeover**: the vendor needs a human step: a CAPTCHA, a two-factor challenge, an unexpected page. Give the human the `takeover_url`. Without one, read the job: at step `email_code` the vendor mailed a verification code to the human's own address, which they chose on the approval; ask the human for it, or read it from their mailbox only when they have given you access for that, and call `relay_code` with the `job_id` and the code. Never guess a code; three at most. - **denied**: stop and tell the human why. One exception: `standing_budget_exhausted` with a `consent_url` means the standing budget this provider would use is spent for the period and the human already has a sheet to raise it; give them that link and ask again once they approve. ## The eight tools | Tool | What it does | | --- | --- | | `request_access` | Asks for access to a provider's resource (an account, an endpoint, a tool) or to a category of pay-per-use tools. Returns granted, pending_consent with a link for the human, provisioning, pending_takeover or denied; with a `request_id`, checks an earlier request instead. | | `get_grant` | The grant for a request that was granted: a proxied base URL and a short-lived token, or the status if it is not granted yet. | | `search_catalog` | Providers and resources Suffect can get access to, with their categories, how they are paid for and whether a price is known before the call. | | `get_quote` | The price of a resource before you use it, when the catalog knows it. | | `list_access` | The human's active approvals that apply to you: what you may use, with budgets and ceilings. | | `set_budget` | Asks for a larger budget under one of your approvals. The human gets a new sheet for the same access with the new budget; nothing changes until they approve it. | | `revoke` | Gives up the access behind one of your requests, now; the grant stops working at the gateway. A whole approval is the human's to revoke, on their dashboard. | | `relay_code` | Passes on the verification code a provider mailed to the human's own address, for a job waiting at `email_code`. | ## Rules - Never print the grant token or a vendor key into chat, files, logs or commit messages. Put it in the environment or pass it directly to the client. - If a call later fails with 401 again, the grant expired or was revoked: call `get_grant` once more. Do not retry in a loop. - When the task is done and you will not need the access again, call `revoke` with the `request_id`. The grant stops at once; the human can always revoke the whole approval on their dashboard. - When you hand the human a link, say in one sentence what they will see: one sheet with the vendor's terms, the plan and price, the budget cap, and one approve button that signs a record with their passkey. - State spend in the request. A call past the budget is refused (a 402 with `mandate_budget`); ask for more with `set_budget` and tell the human why. An approval covers the agent that asked; another agent asks separately. - Never solve a CAPTCHA and never sign up at a vendor yourself. ## Where Suffect is - **The MCP server**: `https://mcp.suffect.com`, remote, OAuth 2.1 with client ID metadata documents and PKCE, so any client registers at the 401 without a developer pre-registering it. - **The skill**: [/skill.md](/skill.md), in the Agent Skills format. Install it where your runtime loads skills; it triggers on 401, 402, 403 and "API key required". - **The CLI**: `suffect`, for terminals and for clients without elicitation: `suffect request`, `suffect env`, `suffect revoke`, `suffect status`. > The production service is not open yet (see [where things stand](/#questions)); the addresses above are where it will answer. ## Reading this site Every page has a Markdown twin at the same path plus `.md` (`/agents.md` for this one), also served when your `Accept` header prefers `text/markdown`. The index is [/llms.txt](/llms.txt); the whole site in one file is [/llms-full.txt](/llms-full.txt); the schemas are under `/schemas/0.2/`; robots.txt allows every agent. --- Canonical: https://suffect.com/agents. Every page of this site has a Markdown twin at the same path plus `.md`; the index is https://suffect.com/llms.txt. # Agent-originated customers, with a human who agreed. Agents already arrive at your signup page looking like fraud. Through Suffect, each one is a real human's account: your terms accepted by version and hash, a budget behind it, and a signed record you keep. - [Read the spec](/spec) - [For site operators](/bot) ## What a signup looks like today - A hosted browser fills your own signup form as the human's tool, after that human approved your terms and a budget with a passkey. - Every request is signed as Suffect (RFC 9421, Ed25519), the User-Agent ends in `SuffectRunner/0.1 (+https://suffect.com)`, and the requests your server handles carry a `Suffect-Attestation` header naming the human's signed record. - A CAPTCHA or a two-factor step goes to the human, never solved. The account's email is an alias Suffect runs for that human, or their own address by their choice. ## Publish one file A manifest at `https://your-domain/.well-known/suffect.json`, served from your own domain over HTTPS, tells Suffect what you sell, which documents a human must accept and how an account is created. The hash is the sha256 of the document's text as the spec normalizes it; the spec package computes it, and the conformance check compares it with your live page. ```json { "suffect": "0.2", "provider": { "name": "Example API", "domain": "example.com" }, "terms": [ { "kind": "terms_of_use", "url": "https://example.com/terms", "version": "2026-06-01", "sha256": "9f3c0a7e5b1d4c2a8e6f0b3d7c9a1e5f2b4d6c8a0e1f3b5d7c9a2e4f6b8d0c1e", "requires": [ "age_18", "authority_if_entity" ], "notices": [ "one_account_per_person" ] }, { "kind": "privacy_policy", "url": "https://example.com/privacy", "version": "2026-05-02", "sha256": "41d7b2c9e8f1a3d5c7b9e2f4a6c8d0b1e3f5a7c9d2b4e6f8a0c1d3e5f7b9a2c4" } ], "pricing": { "currency": "USD", "plans": [ { "id": "developer", "name": "Developer", "price": 0, "period": "month" } ], "url": "https://example.com/pricing" }, "signup": { "level": 3, "endpoint": "https://api.example.com/suffect/signups", "auth": "suffect_jws", "contact_fields": [ "email", "name", "country" ], "idempotency": true } } ``` ## What you publish, what you get What you publish is read from the manifest, never negotiated; `suffect-spec check` prints the level a manifest earns. | You publish | You get | | --- | --- | | nothing | agent-originated signups through Suffect's runner, the same as a human using your site; where Suffect has written a playbook for your site, the sheet names your documents by version and hash | | a manifest with your terms and pricing | exact consent sheets worded from your own manifest, your hashes held to your pages, fewer disputes | | a signup endpoint in the manifest | one-call signups, signed consent records stored with each account, no bot-defense collisions | | MPP or x402 rails | per-request access for agents that do not want an account, paid from the human's budget (planned: Suffect's 402 and MPP rails are not built yet) | ## The signup endpoint - With a signup endpoint in the manifest, Suffect posts one JSON request to it: the human's signed consent record, a five-minute attestation, the plan requested, the contact fields your manifest lists, and the credential scopes. - You verify the attestation and the record's two proofs against `https://suffect.com/.well-known/jwks.json` and check that the record names your current terms. - You answer 201 with the account id and the credential; 409 when the human already has an account; 422 when the terms version is stale. - A reference endpoint in Hono ships with the spec package, and `suffect-spec check your-domain` runs the conformance steps before you publish. ## Verify every request from Suffect - `Signature-Input` and `Signature`: an RFC 9421 signature, Ed25519, five minutes of life, a fresh nonce, the key id being the key's JWK thumbprint. - `Signature-Agent: "https://api.suffect.com"`: the origin that publishes the key directory at `/.well-known/http-message-signatures-directory` and the Signature Agent Card at `/.well-known/signature-agent-card`. - `Suffect-Attestation`: the same five-minute JWS a manifest signup carries; `GET https://api.suffect.com/v1/consents/by-hash/{sha256}` with it as the `Authorization` returns the record it names. > The production service is not open yet (see [where things stand](/#questions)); the spec is at 0.2 and the conformance check runs today against any domain. ## Publish a manifest About ten minutes of your time: the terms you already publish, named by version and hash, in one JSON file. - [Read the spec](/spec) - [The runner, for site operators](/bot) --- Canonical: https://suffect.com/vendors. Every page of this site has a Markdown twin at the same path plus `.md`; the index is https://suffect.com/llms.txt. # Vendor manifest spec 0.2 An open specification for how an API vendor tells an agent's account layer what it sells, which documents a human must accept, and how an account is created with that human's signed consent. Three JSON Schemas, a reference endpoint and a conformance check, under the Apache-2.0 license. - [manifest.schema.json](/schemas/0.2/manifest.schema.json) - [signup-request.schema.json](/schemas/0.2/signup-request.schema.json) - [consent-record.schema.json](/schemas/0.2/consent-record.schema.json) ## Discovery 1. `https://{vendor-domain}/.well-known/suffect.json`: the manifest this spec defines. 2. Optional: the vendor's MCP server lists Suffect's authorization server in the `authorization_servers` array of its RFC 9728 protected-resource metadata, so a client that hits the vendor's 401 lands on the consent sheet. 3. Optional: an entry in the vendor's Agentic Resource Discovery `ai-catalog.json` pointing at the manifest. The manifest must be served from the vendor's own domain over HTTPS. Suffect refuses a manifest served from a third-party host, so a lookalike cannot speak for a vendor. ## The manifest | Field | Required | What it is | | --- | --- | --- | | `suffect` | yes | the spec version the manifest is written to; minor versions are additive | | `provider` | yes | name, domain, legal name, support URL and kind | | `terms` | yes | every document a human must accept: kind, URL, version, the sha256 of the normalized text, what it requires of the human, the notices it carries and the clauses those rest on | | `pricing` | no | currency, plans, packs and the pricing page | | `signup` | no | the level, the endpoint and its authentication, the contact fields, idempotency | | `credential` | no | type, header, scheme, scopes, rotation and the proxy base URL | | `budget` | no | a webhook for budget events, and whether usage events are sent | | `rails` | no | card, mpp or x402 | | `contact` | no | security and partnerships addresses | | `resources` | no | optional: each resource with its own access, pricing, acquisition and, when it has them, terms; without it the manifest describes one account resource acquired through signup | What a manifest declares decides what Suffect can do at the vendor: terms alone let the sheet name the documents by version and hash; terms and pricing make the sheet exact; a signup endpoint makes the signup one call; rails including `mpp` or `x402` will add per-request access once Suffect's payer rails are built. The conformance check prints the level a manifest earns. What each brings, restated for vendors, is on [the vendors page](/vendors#levels). ## How a document is hashed A terms `sha256` is computed over the normalized text: CRLF and CR become LF, runs of spaces and tabs collapse to one space, each line is trimmed, empty lines are dropped, lines join with LF. An HTML page's text is its main content first (the first `main` element, else the first element with `role="main"`, else the first `article`, else the body) with scripts, styles, the head and the page's header, navigation and footer dropped, block boundaries as line breaks and entities decoded; a PDF's text is its pages in order. The reference implementations are `normalizeTerms` and `stripHtml` in the spec package, the one extractor Suffect's snapshot job and its Worker both run, so a vendor and Suffect compute the same hash for the same page. ## The signup request `POST {signup.endpoint}` with `Content-Type: application/json`, an `Idempotency-Key` header and a request signature (below). The body: | Field | Required | What it is | | --- | --- | --- | | `suffect` | yes | the spec version | | `request_id` | yes | unique per vendor; the idempotency key | | `consent` | yes | the human's signed consent record (the third schema) | | `attestation` | yes | a JWS Suffect signs over the record's sha256, the request id, your domain and a five-minute expiry | | `requested` | yes | the plan, packs and budget the human approved | | `contact` | yes | the fields your manifest lists: an alias email or the human's own, name, country | | `credential` | yes | the type and scopes the account's key should carry | | `payment` | no | the rail and, for a card, the issuer's network token | | `resource` | no | the account resource's slug when the manifest lists more than one | - **201 Created**: the account id, the credential (type, value, scopes, when it rotates), the accepted terms by version and hash, and a pricing echo - **202 Accepted**: a status URL; Suffect polls until succeeded, failed or action required with a URL for the human - **409 Conflict**: `account_exists`, with the existing account id for the same human when the vendor can say - **422**: `terms_version_stale`, `plan_unavailable`, `budget_below_minimum`, `representation_missing` or `country_unsupported` - **403**: `attestation_invalid` ## The consent record What a human approved, signed twice: by the human's passkey and by Suffect's Ed25519 key, and chained to the human's previous record. The attestation that accompanies a signup binds this record's hash to that one request at that one vendor for five minutes; a vendor verifies both against the key set at `https://suffect.com/.well-known/jwks.json` and keeps the record with the account. | Field | Required | What it is | | --- | --- | --- | | `type` | yes | the record's type name | | `version` | yes | the record format's version | | `id` | yes | the record's id | | `issued_at` | yes | when it was issued | | `issuer` | yes | Suffect, with the key id of its countersignature | | `subject` | yes | the human, by a stable id, with the representations they made once | | `approver` | yes | the passkey that approved, and when | | `agent` | yes | the OAuth client the approval covers | | `provider` | yes | the vendor's domain and name | | `scope` | yes | the resources, actions and amounts the approval allows, exactly | | `terms` | yes | every terms snapshot the record accepts, by kind, URL, version and sha256 | | `commercial` | yes | the plan or pack and its price | | `budget` | yes | the cap and its period | | `data_shared` | yes | name, alias email or own email, country | | `assent_text` | yes | the sentence the human approved | | `notices_shown` | yes | every notice the sheet printed | | `clauses_shown` | no | the clauses printed under the notices, each keyed to a document in terms | | `proofs` | yes | the passkey's signature and Suffect's Ed25519 countersignature | | `prev` | yes | the hash of the human's previous record | ## Request signatures Every request Suffect's automation sends a vendor (signup requests, reads of a manifest and the terms it cites, and the runner's browser on the vendor's hosts) carries an RFC 9421 HTTP Message Signature (Ed25519) over the authority and the `Signature-Agent` header, with a five-minute window, a fresh nonce and the tag `web-bot-auth`, in the profile Cloudflare's verifier takes. The agent's API calls through the gateway carry the vendor's key, not a signature. `Signature-Agent` names the origin that publishes the key directory, a JWK Set of Ed25519 public keys each proven by a signature over the directory's authority, with the key id as the key's thumbprint. A signature proves that the holder of a published key sent this request to this host within this window, and nothing about the human; the record and the attestation name the human. ## Replay and rotation - `request_id` is unique per vendor; the attestation expires after five minutes; signup requests carry idempotency keys. - A request signature lives five minutes with a fresh nonce; a verifier that wants replay protection inside the window keeps the nonces it has seen for as long. A signature authorizes nothing by itself. - The attestation a browser carries is refreshed at most every thirty seconds per job and only while the job is open; a captured one reads the human's record for the rest of its five minutes and nothing more. - Attestation keys rotate with overlap, `kid` naming the key. Request-signing keys rotate through the directory: published and proven before anything signs with them, kept listed for the directory's max-age plus the longest signature life, then dropped. - Vendors should rate-limit the signup endpoint per subject and per IP, and treat the alias email as the customer's contact. Suffect sends only the contact fields the manifest lists. ## Conformance `suffect-spec check ` fetches the manifest from the vendor's own domain and validates it against the schema (`manifest`), hashes every document the manifest cites against the live page (`terms:`, and `terms::` for a resource's own documents), holds every quoted clause to the fetched text (`clauses:`), and exercises the signup endpoint (`endpoint`). Suffect's own verification runs the same check and then snapshots each document, so a vendor sees the verdict before publishing. ## Schemas The three schemas are served at the `$id` each declares, under `/schemas/0.2/` on this site, byte for byte as the spec package ships them: [manifest.schema.json](/schemas/0.2/manifest.schema.json), [signup-request.schema.json](/schemas/0.2/signup-request.schema.json) and [consent-record.schema.json](/schemas/0.2/consent-record.schema.json). The signup request refers to the consent record by its `$id`. --- Canonical: https://suffect.com/spec. Every page of this site has a Markdown twin at the same path plus `.md`; the index is https://suffect.com/llms.txt. # Your agent gets access, not the keys. Vendor keys stay encrypted in a vault, money will stay with the card issuer, and nothing happens without a record you signed with your passkey. - [Where things stand](/security#not-yet) - [The consent record](/spec#record) ## Who holds what - **You**: Your passkey. It approves every sheet and signs every record. No one approves for you. - **Your agent**: A short-lived token. Scoped to what you approved, used through Suffect's proxy, revocable at once. - **Suffect's vault**: The vendor key, encrypted. A data key per credential, wrapped by a master key held apart from the database, opened only to forward a call. - **The card issuer**: Card numbers and funds. Suffect never stores them: a card number is fetched from the issuer at checkout and held in memory only. The card program is being set up. - **The vendor**: Your account. In your name, with the vendor as the merchant of record. ## Six rules the code keeps ### Access, not the key Your agent gets a proxied base URL and a short-lived token. A raw key leaves the vault only if you choose it on the sheet. ### Nothing without your passkey No test mode, internal flag or partner path creates an account, issues a grant or spends money without an approval you signed. ### Every approval is a signed record Countersigned by Suffect with Ed25519 and chained to your previous record, so it cannot be quietly rewritten. ### Spend capped by your budget Calls Suffect can price are reserved against your budget before they run, in an exact double-entry ledger; once the budget is spent, calls are refused. ### Signed, identified automation Every request Suffect's automation sends a vendor carries an RFC 9421 signature: signups, reads of a manifest and its terms, and the runner's browser. A CAPTCHA or a 2FA step goes to you, never solved for you. ### A small surface Every public route is rate-limited before it does work, the dashboard and this site run no scripts, and credentials never reach a log. ## Reviewed before it ships 1. **One list of sensitive paths** The gateway, the runner, the vault, consent, OAuth, the ledger and this site's key-set proxy are named in one file in the repository. 2. **A threat-model diff with every change to them** What is at risk, what changed in the mitigations, and what was tested, written before the change merges. 3. **An internal audit** An internal audit of the whole codebase on 2026-10-15; every finding was fixed in ten pull requests. ## Where things stand - Done: Proxied, short-lived grants and the encrypted vault - Done: Passkey-signed, countersigned consent records - Done: Signed signups and browser requests at every vendor - Done: Rate limits on every public route - Not yet: A SOC 2 report - Not yet: A penetration test by a third party - Not yet: The service in production - Not yet: The card program, and the key-management root behind the vault (a local key stands in) Done means running on staging, as of 2026-10-20. Found a security problem? Write to [hello@suffect.com](mailto:hello@suffect.com). --- Canonical: https://suffect.com/security. Every page of this site has a Markdown twin at the same path plus `.md`; the index is https://suffect.com/llms.txt. # SuffectRunner, for site operators If `SuffectRunner` appears in your logs, an agent asked for an account at your service on a human's behalf, the human approved your terms and a budget on a consent sheet with a passkey, and Suffect's hosted browser is completing your own signup form as that human's tool. ## What it sends **On every request to your hosts** - **User-Agent**: `the real browser's string with SuffectRunner/0.1 (+https://suffect.com) appended` - **Signature-Agent**: `"https://api.suffect.com"` - **Signature-Input and Signature**: `an RFC 9421 HTTP Message Signature, Ed25519, five minutes of life, a fresh nonce, tag web-bot-auth` - **Suffect-Attestation**: `on the requests your server handles: a five-minute JWS naming the human's signed consent record` ## How to verify it - Fetch the key directory at `https://api.suffect.com/.well-known/http-message-signatures-directory`: a JWK Set of Ed25519 public keys, each proven by a signature over the directory's own authority, with the key id as the JWK thumbprint. Verify the request's signature with the key its `keyid` names. Cloudflare's Web Bot Auth verifier takes this profile as is. - Read the Signature Agent Card at `https://api.suffect.com/.well-known/signature-agent-card`: who the agent is, its purpose, the product token `SuffectRunner` and the one well-known URL it reads at every vendor. - Read the human's record: `GET https://api.suffect.com/v1/consents/by-hash/{sha256}` with `Authorization: Suffect-Attestation ` returns the signed consent record the attestation names, for the five minutes the attestation lives. ## What it does - Fills your signup form with the human's name, country and an email address, an alias Suffect runs for that human or the human's own by their choice, and reads the verification code you mail there. - Pays for nothing today: the card program is not live (see [where things stand](/security#not-yet)), so it signs up only for plans that cost nothing. Once it is live, a plan is paid with a card issued for that human with a limit equal to the budget they approved. - Creates an API key on the human's new account and stores it in a vault; the human's agent never receives it by default. - Reads `/.well-known/suffect.json` on your domain and the terms documents it cites, to verify them. Nothing else is crawled or collected. ## What it never does - Solve a CAPTCHA, pass a two-factor challenge or finish any step your site reserves for a person; those go to the human with a link to take over the live session. - Spoof a fingerprint, hide behind a residential proxy or rotate identities: one product token, one signing origin, one User-Agent suffix. - Leave your domain: the browser is pinned to the hosts of the vendor whose sheet the human approved. - Create more than one account per human at your service, share credentials between humans, or resell access. - Scrape: the form is filled as the human's tool, and no page content is extracted beyond the manifest and the terms. ## How to decline Blocking the product token or any unsigned request at your edge stops the runner at once: it does not retry around a block, and the human is told to finish by hand or to choose another vendor. If you would rather be removed from the registry so no sheet is ever shown for your service, write to [hello@suffect.com](mailto:hello@suffect.com). Publishing a manifest at `/.well-known/suffect.json` does the opposite: it turns these signups into one signed call to an endpoint of yours (see [for vendors](/vendors)). --- Canonical: https://suffect.com/bot. Every page of this site has a Markdown twin at the same path plus `.md`; the index is https://suffect.com/llms.txt. # The agent skill (skill.md) --- name: suffect description: Get access to an API vendor (search, scraping, video, voice, inference, any paid API) with the human's one-time approval, instead of asking them to paste an API key. Use when a request fails with 401, 402, 403 insufficient scope, or documentation says an API key, account or subscription is required. --- # Suffect Suffect signs a human up at a vendor on your behalf after they approve the vendor's terms and a budget once. You then get a scoped, short-lived grant, usually a proxied base URL plus a token, never the vendor's long-lived key. ## When to use it - A vendor API answers 401, 403 with an insufficient-scope message, or 402. - A vendor's docs say "get an API key", "create an account" or "subscribe". - The task needs a capability no connected vendor provides. Do not ask the human to paste a key. Do not sign up at the vendor yourself. Do not solve CAPTCHAs. ## What to do 1. Call the Suffect MCP tool `request_access` with the provider's domain or slug and a budget if the task implies spend (for example `{ "provider": "exa.ai", "budget": { "amount": 20, "currency": "USD", "period": "month" } }`). Without MCP, run `suffect request exa.ai --budget 20/mo --json` with your access token in `SUFFECT_TOKEN`. - A catalog row whose terms carry `automated_signup_restricted` or `signup_on_behalf_restricted` (with the clause quoted under `clauses`) means the provider's terms restrict what you are about to ask for. Tell the human so in one sentence before requesting; the sheet shows the clause and their approval acknowledges it in the signed record. Suffect still proceeds, openly, as their identified agent. 2. Read the response, and keep its `request_id`: - `granted`: call `get_grant` with the `request_id` (or `suffect env `) and use the returned base URL and token. Point the vendor SDK at the base URL; send the token as the bearer credential. - `pending_consent`: tell the human in one sentence what you asked for and give them the `consent_url`. Wait, then check with `get_grant` (or `request_access` with the `request_id`). - `provisioning`: approved, and the account is being created. Check again with `get_grant` in a minute. - `pending_takeover`: the vendor needs a human step (CAPTCHA, 2FA, an unexpected page). Give the human the `takeover_url`; check with `get_grant` after they finish. Without a `takeover_url`, read the job (`job_id`): at step `email_code` the vendor mailed a verification code to the human's own email address, which they chose on the approval; ask the human for the code, or read it from their mailbox only when they have given you access for this, and call `relay_code` with the `job_id` and the code (or `POST /v1/jobs/{job_id}/code`). Never guess a code; three at most. On the default, a Suffect alias, no code ever passes through you. - `denied`: stop and tell the human why. One exception: `reason` is `standing_budget_exhausted` and a `consent_url` is given, which means the standing budget this provider would use is spent for the period and the human already has a sheet to raise it; give them that link and ask again once they approve. 3. Never print the grant token or a vendor key into chat, files, logs or commit messages. Put it in the environment or pass it directly to the client. 4. If a request later fails with 401 again, the grant expired or was revoked: call `get_grant` once more. Do not retry in a loop. 5. When the task is done and you will not need the access again, call `revoke` with the `request_id`. The grant stops working at once; the human can always revoke the whole approval on their dashboard. ## What the human sees A consent sheet with the vendor's terms (version and hash), a plain-language summary marked as not the agreement, the plan and price, the budget cap, the data shared, and one approve button that signs a consent record with their passkey. Say so when you hand them the link, in one sentence. ## Budgets State spend in the request. The human approves a budget, and calls Suffect prices before they run are refused once it is spent (a 402 with `mandate_budget`). If the task needs more, call `set_budget` with the `mandate_id` from `list_access` and the budget you need: the human gets a new sheet for the same access with the larger budget, and nothing changes until they approve it. Tell them in one sentence why. An approval covers the agent that asked for it; another agent asks separately.