Build an iMessage agent that can actually buy things.
Text a phone number, and an AI agent replies: it chats, it shops, and it pays with a virtual card it creates on the spot. This template is the working skeleton of that product, the same architecture behind Agentcard's own iMessage line, reduced to the parts you need and nothing else.
you: get me a burrito
agent: quick one time check so i can act on your behalf: i just texted
a 6 digit code to •••• 0134. reply here with that code.
you: 482913
agent: you're verified.
agent: found a few spots near you. chipotle (~$12) or the taqueria on
24th (~$14)?
you: chipotle. checkout
agent: order placed. $12.40 on a one time virtual card, arriving ~7:40pm.
iMessage ──▶ Photon (spectrum-ts) ──▶ this relay
│
1. sign the sender in (SMS OTP → OAuth)
2. run a Claude tool-use loop
│
▼
Agentcard MCP server (mcp.agentcard.sh)
buy · create_card · check_balance · KYC · …
Three services, three keys:
- Photon provides the iMessage phone number and the spectrum-ts SDK (a persistent stream, so this runs anywhere, no public URL needed).
- Agentcard provides money: each sender signs in as their own consumer Agentcard account by SMS code, and your agent drives every tool the Agentcard MCP server advertises with that user's OAuth token. Cards your agent creates are isolated to your app and that user, funded from their own wallet.
- Anthropic provides the brain: a Claude tool-use loop that binds whatever tools the MCP server advertises and picks per message.
The relay itself stays thin on purpose. Shopping intelligence (carts, checkout confirmation, merchant connections) lives server-side behind the buy tool; identity and compliance (KYC, funding) live in Agentcard. What this repo owns is the conversation: transport, sign-in, the tool loop, and the safety rails around it.
git clone https://github.com/tiny-agent-company/imessage-agent-template.git
cd imessage-agent-template
cp .env.example .env
npm install
npm run devFill .env in three stages, testing as you go:
1. The pipe. Create a Photon project, put PHOTON_PROJECT_ID + PHOTON_PROJECT_SECRET in .env, and text your line. The relay echoes back: the pipe works.
2. The money. Create your Agentcard org and OAuth client (one-time, ~2 minutes):
npm i -g agent-cards-admin
agent-cards-admin login
agent-cards-admin orgs create --name "My iMessage Agent"
agent-cards-admin oauth-clients create --name "My iMessage Agent" \
--redirect-uri "https://example.com/oauth/callback"Put the printed client id and acs_ secret in .env (AGENTCARD_OAUTH_CLIENT_ID, AGENTCARD_OAUTH_CLIENT_SECRET, and AGENTCARD_OAUTH_REDIRECT_URI matching what you registered). The redirect URI is never navigated, sign-in completes over SMS, but OAuth requires it to match.
New clients start in sandbox mode: everything works, but the cards your agent creates are test cards. When you're ready for real spending, subscribe the org (agent-cards-admin subscribe) and register a production client (agent-cards-admin env production, then oauth-clients create again).
3. The brain. Put your ANTHROPIC_API_KEY in .env.
Restart, text your line again, and you're talking to the real agent: it sends you a 6-digit code, you reply with it, and from then on it can shop and manage cards for you. This is the documented messaging agent flow, end to end.
You can also verify the Agentcard leg without any iMessage line: scripts/e2e-live.mts drives the same sign-in and agent code from your terminal (start <phone> sends you the code, verify <code> completes sign-in and smoke-tests the MCP session, turn "hi" runs one full agent turn).
- Voice: every word the agent says lives in
src/persona.ts, both the model's personality and the fixed sign-in copy. Edit one file, own the product. - Model:
AGENT_MODELin.env(Sonnet by default: fast and near-Opus quality, the right tradeoff for a snappy texting UX). - Storage: sender auth state persists to a JSON file (
STATE_FILE), so there is no database to run. The store is one small interface (src/lib/store.ts); swap in Postgres or SQLite when you outgrow a file. - Tools: the loop binds every tool the MCP server advertises, so new Agentcard tools appear in your agent automatically. Nothing stops you from binding additional MCP servers or local tools alongside it.
- Deploy: it's one long-lived Node process (the Photon stream needs to stay open). The
Dockerfileworks on any container host: Fly, Railway, Render, ECS, a VPS.
Agents that touch money need boundaries that don't depend on the model behaving. The template ships three, all enforced in code:
- The token never reaches the model. The sender's OAuth access token is sent only to the Agentcard MCP server. Anthropic sees tool definitions and tool results, never credentials.
- Card secrets are redacted. Tool results pass through a two-layer mask (sensitive field names, plus a card-number pattern backstop) before the model sees them. Full card numbers and CVVs never enter the conversation, in either direction.
- Money moves only with consent. Tools that spend or change cards (
create_card,fund_wallet,pay_checkout, …) are held, not executed, until the user explicitly confirms that exact call (same tool, same arguments) on a later message. Holds expire after 10 minutes. The conversationalbuytool is exempt because it gates its own checkout server-side the same way.
Also there because texting is messier than it looks: at-least-once message dedup with crash-safe release, OTP extraction that won't mistake "$25" for a code, token refresh ahead of long turns, sign-in parking for unsupported countries (so a rejected sender isn't stonewalled with the same reply forever), markdown rendered to iMessage-safe plain text (links included), a typing indicator that survives multi-bubble turns, and a reconnect loop with backoff for the stream.
It's a starting point, not our production system. It runs one process with a JSON file for state; our production relay adds Postgres, multi-instance claim recovery, delivery retries, streaming turns, image/KYC handling, and a lot of operational scar tissue you won't need on day one. When you do, the seams are where you'd expect (the store, the dedup, the transport), and the Agentcard docs cover the platform side.
MIT. Built by Agentcard.