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.
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 aSuffect-Attestationheader 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.
{
"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
| 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) |
suffect-spec check prints the level a manifest earns.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.jsonand 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-domainruns the conformance steps before you publish.
Verify every request from Suffect
Signature-InputandSignature: 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-directoryand 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 theAuthorizationreturns the record it names.
Publish a manifest
About ten minutes of your time: the terms you already publish, named by version and hash, in one JSON file.