Send a letter from an AI agent in a minute, with no account
FrankKi runs a public MCP lane with no sign-in: seven tools, three calls, one Stripe link. The full walkthrough with real production output, the prices, and the rules the lane enforces in code.
An AI agent can put a real paper letter in the post through FrankKi with no account, no API key, and nothing to install. The public MCP lane sits at https://mcp.frankki.app/api/mcp/v1/public, it exposes seven tools, and the path from an empty page to a payable checkout link is three calls. Payment happens once per letter, through a Stripe link the agent hands back into the conversation.
I ran the whole thing against production while writing this. One page, Berlin to Munich, 3.49 EUR, checkout link in hand, well under a minute. Nothing asked me for an email address, a password, or a token.
Seven tools, no login
The lane keeps its own hand-written tool list. That sounds like housekeeping, but it's the reason a business-account tool can never leak out here: if a tool isn't on the list, it doesn't exist publicly. All seven carry securitySchemes: [{ "type": "noauth" }].
| Tool | What it does | Needed for the short path? |
|---|---|---|
letter_quote | Lists shipping methods and prices for a destination | optional |
address_check | Checks a recipient address | optional |
letter_compose | Builds the draft from sender, recipient, subject, body | yes |
letter_preview | Returns page images of the finished letter | yes |
checkout_link | Mints the Stripe checkout link for that exact draft | yes |
order_track | Shows shipment status for the private tracking token | afterwards |
upgrade_info | Explains what an account adds after a guest purchase | no |
The short path is three calls
Sender, recipient, text. That's all the first call needs, because everything else has a default: black and white, standard letter, German language.
- letter_compose renders the letter and returns a
draftToken. That token is the thread the next two calls hang on, and it lives 24 hours. - letter_preview turns the pages into images. Skip it and there is no checkout link, more on that below.
- checkout_link returns a Stripe checkout URL and the amount in cents. The agent posts the URL, the human pays by card, Apple Pay, Google Pay, or Link.
One detail that otherwise costs you ten minutes. The endpoint speaks Streamable HTTP and insists on both accept types. Leave out text/event-stream and you get a 406 saying "Client must accept both application/json and text/event-stream". That's the MCP transport rule, not something FrankKi invented.
The actual run, call by call
Everything below is trimmed output from the 2026-08-21 run. Tokens are shortened, nothing else was changed.
curl -X POST https://mcp.frankki.app/api/mcp/v1/public \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{
"name":"letter_compose",
"arguments":{
"subject":"Kurze Nachricht",
"content":"Hallo, ich melde mich kurz und wuensche dir eine gute Woche. Viele Gruesse",
"sender":{"name":"Pascal Lindenau","street":"Musterstrasse","houseNumber":"1","zip":"10115","city":"Berlin","country":"DE"},
"recipient":{"name":"Maria Beispiel","street":"Beispielweg","houseNumber":"2","zip":"80331","city":"Muenchen","country":"DE"}
}}}'
The response already carries everything the agent can report back:
{"status":"success","code":"OK","data":{
"draftToken":"k3nyw8jAeVNBKto4...",
"trackingToken":"JM36mwCfmnE3xTx7...",
"version":1,
"deliveryType":"standard",
"color":false,
"method":{"code":"standard","nameEn":"Standard letter","deliveryTimeEn":"1 to 2 business days","tracked":false,"proofOfDelivery":false},
"previewReady":false,
"reviewPending":false}}
Then the preview, using that draftToken. It returns one signed image URL per page, valid for half an hour:
"pages":{"tokenExpiresAt":"2026-08-21T10:05:08.073Z",
"items":[{"page":1,"url":"https://mcp.frankki.app/api/mcp/v1/public/page?token=eyJhbGciOiJIUzI1NiJ9..."}]}
And the till:
{"status":"success","code":"OK","data":{
"checkoutUrl":"https://checkout.stripe.com/c/pay/cs_live_a120IQWj2PfN...",
"sessionId":"cs_live_a120IQWj2PfN...",
"amountCents":349,
"deliveryType":"standard",
"shipping":"Versand als Standardbrief, schwarz-weiss gedruckt."}}
Three calls, 349 cents, one link to pass on.
What a guest letter costs
The price is never computed in the agent. It comes from the same shipping policy that serves the iPhone app, and letter_quote hands it out fresh before every send. An agent that hardcodes a price will be wrong eventually, so the call is cheaper than the assumption.
| Method | Price | Tracked | Proof of delivery |
|---|---|---|---|
| Standard letter | 3.49 EUR | no | no |
| Registered, drop-in | 7.59 EUR | yes | yes |
| Registered, hand delivery | 8.19 EUR | yes | yes |
Transit time for the standard letter inside Germany is roughly 1 to 3 business days. If you need registered mail with real posting evidence, the longer workflow lives in how to send registered mail from an AI agent.
Six rules the lane enforces in code
An anonymous lane that prints real paper and collects real money needs edges. These are wired into the handlers, not promised in a doc.
- No preview, no checkout.
checkout_linkcalls the preview again itself and refuses withPREVIEW_REQUIREDwhen no page image exists. Nobody should pay for a sheet they never saw. - Paid first, printed second. The only trigger for submission is Stripe's
checkout.session.completed. Before the money lands, the print provider sees nothing. - Sender and recipient worldwide. Printing and posting always happen in Germany; the sender country is only the return address on the letter.
- Drafts live 24 hours. After that the
draftTokenis worthless and a cleanup cron collects the row. - Every draft passes a content screen. Impersonation of authorities, banks, and debt collectors gets rejected, borderline cases go to a human, and the checkout link only appears after release. An angry but perfectly legitimate cancellation letter must not trip it, and the list was tuned against exactly that.
- No invented prices. If a destination has no priceable method, the lane refuses instead of estimating.
The account is created at the till, not before it
Stripe asks for an email address because it needs one for the receipt. After the purchase that address becomes a magic link, and the profile it opens is the same one Apple Sign-In would have created. Same address, same person, one profile. Someone who never clicks still sent a letter and keeps the private tracking token for order_track.
Where the public lane stops
It's deliberately narrow. No balance, no client separation, no templates, no letterhead, no archive, no volume tiers. One letter, one recipient, one payment. But once you send regularly, you're overpaying: the guest price is 3.49 EUR, while on the partner tariff a German standard letter runs between 2.49 and 1.49 EUR depending on monthly volume, and the ladder starts at 20 letters a month.
That's what the second lane is for, the one with sign-in, an approval queue, and a wallet. Its tool list is several times longer. Start at the developer documentation, the B2B pricing page, or the MCP overview. And if you first want to see who else ships paper from an agent, eight providers are lined up here with a check date on every row.
Direct sources used to research and verify this guide.
- FrankKi public MCP lane Primary source
- FrankKi developer documentation Primary source
- FrankKi MCP overview Primary source
- MCP specification, Streamable HTTP Primary source
- Does an AI agent need a FrankKi account to send a letter?
- No. The public MCP lane at https://mcp.frankki.app/api/mcp/v1/public runs without sign-in and without an API key; all seven tools are declared noauth. The agent builds the draft, fetches the preview, and gets a Stripe checkout link back. An account is only created after the purchase, through a magic link sent to the email address from the Stripe checkout, and even that is optional.
- What is the minimum number of calls per letter?
- Three: letter_compose with sender, recipient, subject and body, then letter_preview with the returned draftToken, then checkout_link. letter_quote and address_check are useful but not required. Everything else has a default: black and white, standard letter, German language.
- What does a guest letter cost?
- On 2026-08-21 a one-page standard letter to Germany costs 3.49 EUR, registered drop-in 7.59 EUR, and registered hand delivery 8.19 EUR. Prices resolve server-side from the shipping policy, and letter_quote returns them fresh before every send, so an agent should never hardcode a price.
- Why does the endpoint answer with 406?
- The Accept header is incomplete. Streamable HTTP requires application/json and text/event-stream together; leave one out and the transport answers 406 with 'Client must accept both application/json and text/event-stream'. That is an MCP transport rule rather than a FrankKi quirk.
- Can anything get printed before payment?
- No. The only trigger for submission is Stripe's checkout.session.completed. Before that, the print provider never sees the letter. The amount is authorized at checkout and captured later, following the same capture chain as the iOS app.
- Where can a guest letter go?
- Sender and recipient can both be anywhere. Printing and posting always happen in Germany, so the sender country is only the return address on the letter. Recipients are worldwide as long as the destination has a priceable shipping method. When there is none, the lane refuses instead of estimating a price.
- How long does a draft live?
- 24 hours. After that the draftToken is worthless and a cleanup cron removes the row. The signed preview images expire sooner, half an hour from the letter_preview call.
