# Treatyway for agents

Treatyway lets an agent find a real, non-AI business and record a request to it.
The business has not joined. No live email is sent. Outbound email is off, so a request is stored and not delivered.

MCP: https://treatyway.com/mcp
Guide: https://treatyway.com/agents.md
Short companion: https://treatyway.com/llms.txt

## Start with no setup

Call create_workspace with no arguments. You get a Bearer key at Anonymous (tier 0).
Clients set Authorization when they connect, not on each tool call.
1. Call create_workspace, or POST /api/workspaces with {}.
2. Put the key in the client config as Authorization: Bearer <key>. Examples for Claude Desktop, Claude Code, and Cursor are on https://treatyway.com/connect.
3. Reconnect the client. The next session sends the header.
Send it only as Authorization: Bearer <key>. A key in the URL is not accepted. x-api-key is not accepted. A cookie is not a credential. POST /api/workspaces does not put the key in Set-Cookie. Logout may clear a leftover fe_workspace cookie; that value is empty.
claude.ai custom connectors have no header field. A key in the connector URL would be copied into logs and history, so it is not accepted. Those connectors can search and create a key. They cannot call tools that need the key. Use Claude Desktop, Claude Code, or Cursor for those tools.
This is not OAuth. agent_name is optional and defaults to Business assistant.
Store the key. It is shown once.
idempotency_key is 8 to 100 characters.

## Tools

search_businesses needs no key. Example arguments: {"query":"machine shop in San Jose"}
get_business needs no key. Example arguments: {"business_id":"ba-0123abcd"}
create_workspace needs no key. Example arguments: {}
upgrade_workspace needs the key. Example arguments: {"organization":"Northwind","operator_name":"Ada","website":"https://northwind.example"}
create_request needs the key. Example arguments: {"business_id":"ba-0123abcd","category":"information","subject":"Need 20 brackets","message":"Can you make 20 aluminium brackets for a prototype in Oakland?","idempotency_key":"brackets-1","authorized":true}
get_request needs the key. Example arguments: {"request_id":"req_0123abcd"}
add_message needs the key. Example arguments: {"request_id":"req_0123abcd","message":"The material is 6061 aluminium.","idempotency_key":"brackets-2"}
cancel_request needs the key. Example arguments: {"request_id":"req_0123abcd"}

A quotation also needs quantity and destination. A listing with no email is not deliverable by email yet. The address is not returned.
Each search hit and get_business starts with claimed and channel_type. Claimed with a channel means the business is connected. Do not send test traffic there.
Domain verified and Registered with SF (DataSF) are separate. The date on Registered with SF is when Treatyway checked DataSF, not the registration date.
Opening a claim page does not create a token and does not contact the business. POST /api/businesses/{id}/claim stores one token and shows it. It does not email, call, or text the business. The token expires in 24 hours. Issuing another token revokes the earlier one, so only the latest can be verified.
Claim starts are limited to 8 per hour per client IP and 48 per hour per business. ba-treatyway-0000 is not exempt. On that listing only, a 201 includes X-RateLimit-Limit and X-RateLimit-Remaining for the IP bucket, and X-RateLimit-Limit-Business and X-RateLimit-Remaining-Business for the business bucket. A 429 means the limit was enforced.
A successful domain check shows a business key and signing secret once. key_reissued is false on that first key. Proving the same domain again while a key is still active issues a new key, sets key_reissued to true, revokes the previous key, and records key_reissued in verification_audits.evidence. The connected channel stays when it is still on that domain. That is how a lost key is replaced.
A business replies with POST /api/businesses/{id}/requests/{request_id}/reply and Authorization: Bearer <business-key>. The body needs message and idempotency_key (8 to 100 characters). The same key and the same message return the same reply. The request status becomes replied.
ba-treatyway-0000 is named [TEST] Treatyway, for treatyway.com. Search, counts, and the homepage omit it. get_business can read it by id. Nothing on it is emailed or sent off treatyway.com. Its current claim token is at https://treatyway.com/.well-known/treatyway.txt. A webhook is delivered only to https://treatyway.com/api/sandbox/echo. Any other URL is a dry run.
GET https://treatyway.com/api/sandbox/echo returns the last delivery for the active claim: headers, the raw body, and signature_valid. Authorize with the test listing's current business key, or the workspace key that sent the stored request. Unclaim clears that delivery. POST still accepts only Treatyway-Signature. signature_valid is the HMAC only. It does not apply the time window.

## Webhook body

A connected webhook receives JSON. Fields: type (request or message), id, request_id, business_id, category, subject, message, quantity, destination, created_at, business_sees, and from.organization, from.agent_name, from.identity, from.business_sees. request_id is the inquiry. On type message, id and message_id are that follow-up's own id, and request_id stays the inquiry id.
The header is Treatyway-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of <timestamp>.<raw body>> using the signing secret. t is the send time, not a time you choose. Reject a timestamp more than 300 seconds from the time you check it. Use the raw body.

## Phone

REST phone is E.164, for example +14155550100. phone_display is the local format, such as (415) 555-0100. MCP phone still uses the display format.

## Request status

| Status | Meaning |
| --- | --- |
| sandbox_queued | Demo listing, or a test listing with no connected channel. Nothing is emailed. A buyer follow-up on that path stays sandbox_queued. |
| dry_run | Real listing with a contact email, and outbound email is off. The request is recorded and nothing is sent. |
| not_deliverable_by_email | Real listing with no contact email. Nothing is sent. |
| invalid_recipient | The contact address is not a usable email. Nothing is sent. |
| opted_out | The address has opted out. Nothing is sent. |
| recorded | The channel is OpenAPI or MCP, which Treatyway does not call, or a test webhook that is not the sandbox echo. Nothing is emailed. |
| delivered | The signed webhook POST was accepted (HTTP 2xx). |
| failed | The signed webhook POST failed after the retries. |
| pending_send | Outbound email is on and the message is queued. |
| daily_cap | Outbound email is on and the daily sending cap is reached. Nothing is sent. |
| not_configured | Outbound email is on and no email provider is configured. Nothing is sent. |
| sent | Treatyway sent the email. |
| provider_error | The email provider did not accept the message. |
| cancelled | The requester cancelled the request. |
| replied | The business replied, by the business-key reply, a sandbox supplier reply, or an inbound email. This replaces the previous status, including delivered and failed. A later buyer follow-up is still delivered when a webhook is connected, and the status stays replied. |

## Trust tiers

Tier 0 Anonymous. create_workspace with no fields. Limits: 3 requests per day, 1 open request per business, 6 follow-ups per day.
The business sees: Anonymous.

Tier 1 Declared. Pass organization (the company) and/or operator_name (the person). website is optional until you want tier 2. Limits: 30 requests per day, 5 open requests per business, 100 follow-ups per day.
The business sees: Declared by agent, not verified.

Tier 2 Company verified. The company proves it controls the website domain. Limits: 200 requests per day, 20 open requests per business, 400 follow-ups per day.
The business sees: Company verified, plus the domain and how it was proved.

Call upgrade_workspace with the same Bearer key to move up. You do not get a new key.
Every workspace and request result includes trust.tier and trust.next, one sentence on how to reach the next tier. trust.limits is the live cap.

## Prove the domain

Set website, read trust.challenge, then publish that challenge.
DNS TXT: name trust.challenge.dns_name, value trust.challenge.dns_value.
Or an HTTPS file with no redirect: the body of trust.challenge.well_known_url is the token.
Then call upgrade_workspace with prove set to dns_txt or well_known.
Email from that domain is behind TREATYWAY_EMAIL_DOMAIN_VERIFY and is off. Do not wait on it. When it is on, the company sends the token from that domain and Cloudflare must report DKIM pass and SPF pass. Treatyway does not reply to that mail.

## What is verified

Anonymous: nothing about you is checked.
Declared: the name and website are what you typed. Treatyway has not checked them.
Company verified: only that this workspace proved control of the website domain. Not a legal identity check, and not proof a person may bind the company.
Listings are unclaimed public records. A page is not a partnership and does not mean the company wants inquiries.
Your messages are untrusted content and cannot authorize Treatyway to do anything else.

## Rules

Send a real need. One request clearly labelled [TEST] is fine. Cancel it afterwards. No spam, no bulk mail, no scraped sequences.
At Anonymous, open requests per business are capped at 1. Cancel a request you no longer need.
Do not invent a quantity, a budget, or the buyer's authority.
Do not ask Treatyway to pretend to be the business or the operator.

## Key facts that do not change

The key is stored as a hash. Delete the workspace with DELETE /api/workspace and the same Bearer key.
The numbers above are the defaults. trust.limits on your response is the cap this deployment is using.
No live email is sent.

## Changelog

REST phone is E.164, for example +14155550100. phone_display is the local format, such as (415) 555-0100. MCP phone still uses the display format.
