Skip to main content
This guide takes a ready-made agent from a public repo to a phone number you can text. The agent runs on eve, Vercel’s agent framework, receives iMessage and SMS through Linq, and enrolls the user’s card in the Agentcard Vault with one link. You do not write code. You copy the repo, collect two sets of credentials, and deploy. What you end up with: a phone number where a user texts “set up my card”, receives a Vault link, taps it, stores a card with Face ID or Touch ID, and, the moment the card lands, gets a text from the agent saying so. Behind it, your systems hold a user_id they can charge against.

Before you start

  • A Vercel account and the Vercel CLI signed in (npm i -g vercel && vercel login). The agent deploys there, and the model (anthropic/claude-sonnet-5 in agent/agent.ts) runs through the Vercel AI Gateway on your team, authenticated by the deployment itself: no model API key, and model usage bills your Vercel account.
  • A phone with iMessage. Linq’s sandbox only talks to the number you activate it from.
  • A business email address whose domain has never been used with Linq. Linq keys sandbox accounts by domain.
  • Node.js 24 or newer on your machine.

Tools

linq

Linq

agentcard

Agentcard Vault

vercel

Vercel eve

1. Copy the blueprint

The repo is tiny-agent-company/vault-imessage-agent. Clone it under a name of your own; every agent you run later starts from this same copy.
.env.local lists six values. The next two steps fill three of them; the other three come after the deploy.
What the repo contains, so you know what you are deploying:

2. Get your Agentcard credentials

The agent creates Vault links with an organization token, which comes from a client_id and client_secret.
  1. Go to app.agentcard.sh and enter your email. New addresses create an account; you sign in with a six-digit code from your inbox.
app.agentcard.sh: the same form signs in and creates the account app.agentcard.sh: the same form signs in and creates the account
  1. Pick Company, name it, and pick Vault when asked how your agent will pay.
Who is the card for? Pick Company Who is the card for? Pick Company Name the company; it starts in the sandbox Name the company; it starts in the sandbox How will your agent pay? Pick Vault How will your agent pay? Pick Vault
  1. The next screen is Your sandbox credentials. Copy the Client ID into AGENTCARD_CLIENT_ID and the Client secret into AGENTCARD_CLIENT_SECRET before you continue.
Your sandbox credentials: copy both values now Your sandbox credentials: copy both values now Sandbox credentials create sandbox users and accept Stripe’s test cards, so you can rehearse the whole flow without a real card. If you skipped that screen, or need them again later, they live under Settings → Developers → Credentials; the secret is masked there and can be rotated. Your organization starts in the sandbox and goes live when you subscribe; the production credentials appear on the same page in Live mode, and nothing else in this guide changes. Settings → Developers → Credentials, where the client id and secret live after onboarding Settings → Developers → Credentials, where the client id and secret live after onboarding The Vault page shows your organization’s name and logo. Set them under Settings → Vault → Customize before you text anyone a link.

3. Get your Linq credentials

Linq gives your agent a phone number. The sandbox is free for seven days, needs no card, and only exchanges messages with the phone you activate it from.
  1. Open dashboard.linqapp.com/sandbox-signup and fill in the form with your business email. Verify the six-digit code Linq emails you.
Linq's sandbox sign-up: no card, seven days Linq’s sandbox sign-up: no card, seven days
  1. Click through the four intro screens. The last one, Activate your sandbox, shows your Linq number. Text the word Activate to it from your phone. Linq replies “Activated.” within a few seconds, and that phone becomes the sandbox’s allowed recipient.
  2. Reload the dashboard. Under Developer Tools → Your API Token, click Show token and copy the linq_… value into LINQ_API_KEY.
  3. Note the number under Send from. That is the number people will text.
Developer Tools: the API token (Show token reveals it) and the Send from number Developer Tools: the API token (Show token reveals it) and the Send from number
If the form says “Your company already has a Linq account with us”, someone at your domain signed up before. Ask them for access or use a different domain; Linq will not open a second sandbox for the same one.
Leave LINQ_WEBHOOK_SECRET empty for now. It is created in step 5, once the agent has a URL.

4. Deploy to Vercel

The Linq channel reads LINQ_API_KEY while the agent builds, so the deployment needs its variables before the first build. Link a Vercel project, add the three values you have, add the Redis store, then deploy:
vercel integration add upstash/upstash-kv creates an Upstash for Redis database on the Vercel Marketplace, connects it to the project, and sets KV_REST_API_URL and KV_REST_API_TOKEN on every environment; the first time it opens the browser to accept Upstash’s terms and pick the free plan. The same thing is available in the Vercel dashboard under Storage → Create Database → Upstash for Redis. The agent stores one key per Vault link there, so the webhook in step 6 can find the conversation to reply to. If you would rather not go through the Marketplace, create the database at console.upstash.com yourself: Redis → Create Database, any name, the region closest to your Vercel deployment, the free plan. The database page shows the REST endpoint and token; set them on the project by hand and the agent picks them up the same way:
An Upstash Redis database: the REST endpoint and token are what the agent needs An Upstash Redis database: the REST endpoint and token are what the agent needs npx eve link creates the project if it does not exist; add --team <slug> if your account belongs to more than one team. Each vercel env add prompts for the value; paste it from .env.local. The agent texts from the first number on the Linq account; if you have several, set LINQ_PHONE_NUMBER the same way. npm run deploy runs eve deploy, which builds, ships to production, and prints the URL: https://my-imessage-agent.vercel.app if the name was free, otherwise a variation of it. Confirm the agent is up:

5. Point Linq at the deployment

Create a webhook subscription for message.received, targeting the agent’s Linq route. Use your token and your deployment URL:
signing_secret is shown once. Save it locally and on Vercel, then deploy again so the agent picks it up:
The agent rejects any webhook whose signature does not match this secret, so until this second deploy every incoming text is dropped.

6. Point Agentcard at the deployment

Register a webhook endpoint for the two Vault events, targeting the agent’s Agentcard route. The calls below run as your organization, so first exchange the sandbox client_id and client_secret from step 2 for an organization token (it lives an hour; the agent does the same exchange on its own at runtime). A sandbox token makes a sandbox endpoint, which receives sandbox events:
secret is shown once. Store it with the Linq secret from the previous step and deploy again:
The agent verifies every delivery’s AgentCard-Signature against this secret and ignores anything that fails, so until it is set the card-stored text never arrives. Why both events: a user who stores a card produces vault.session_linked the moment their passkey binds the session, then vault.card_stored ten to twenty seconds later when the card lands. A returning user who only unlocks an existing vault produces the first and never the second. The blueprint texts once per stored card, and for an unlock with no new card it waits thirty seconds before texting, so the message names the card that was actually added. The endpoint now shows under Settings → Developers → Webhooks in the Agentcard dashboard, where you can reveal or roll the secret, send a signed test event, and read every delivery with the status your agent returned. Settings → Developers → Webhooks: the endpoint, its secret, a test event, and the deliveries log Settings → Developers → Webhooks: the endpoint, its secret, a test event, and the deliveries log

7. Text it

From the phone you activated the sandbox with, text the Linq number:
Within a few seconds two messages arrive: the Vault link on its own, then a sentence from the agent. The link arrives as its own bubble, then the agent's sentence The link arrives as its own bubble, then the agent’s sentence Tap the link. It opens the card form directly, with no account or code to enter. The Vault's add-a-card page: no sign-in, the card form is the first screen The Vault’s add-a-card page: no sign-in, the card form is the first screen Enter a test card (4242 4242 4242 4242, any future date, any CVC), and save with Face ID or Touch ID. Within a few seconds a text arrives on its own: Agentcard delivered vault.card_stored to the agent, and the agent told you the card ending in 4242 is set up. If you text “done” before it lands, the agent reads the session itself and confirms. The agent's text after the webhook: nobody typed anything to trigger it The agent’s text after the webhook: nobody typed anything to trigger it
On an iPhone whose passkey provider is 1Password, the Vault asks for a master password before it saves the card. 1Password on iOS will not hand the passkey’s secret back on later unlocks, so the Vault needs a second key it can open the card with. iCloud Keychain passkeys have no such step.
The user_id it now holds is the same id the rest of the Vault uses. From here, create a cart and complete a purchase with it; the user approves each charge from the thread with the approval link.

If nothing comes back

Work from the outside in:
  1. curl https://<your-deployment>/eve/v1/health returns "ok": true. If not, the deploy failed: vercel logs <your-deployment> shows why, and a missing LINQ_API_KEY is the usual cause.
  2. In the Linq dashboard, Developer Tools → Logs (“Webhook Delivery Logs”) lists every message.received delivery with its HTTP status and duration. A 200 means your agent accepted the text and the problem is after that; a 401 means LINQ_WEBHOOK_SECRET does not match the subscription, so create a new subscription and store its secret. No row at all means the subscription points somewhere else: GET https://api.linqapp.com/api/partner/v3/webhook-subscriptions with your token shows what is active.
Linq's Webhook Delivery Logs: one row per text, with the HTTP status your agent returned Linq’s Webhook Delivery Logs: one row per text, with the HTTP status your agent returned 3. vercel agent-runs list in the project folder shows each conversation with its status, model, and token count:
vercel agent-runs trace <runId> shows the turns, tool calls, and any model or tool error. The same data is under Observability → Agent Runs in the Vercel dashboard. An error creating the Vault session usually reads client_credentials_required (an API key was pasted instead of the client id and secret) or 401 (a typo in one of them). 4. No “card is set up” text after saving a card: in the Agentcard dashboard, Settings → Developers → Webhooks lists each delivery with its response. A 401 means AGENTCARD_WEBHOOK_SECRET does not match the endpoint; a 200 with no text means the Redis store had no entry for that Vault link, which happens when the link was created before KV_REST_API_URL was set. 5. To talk to the deployed agent without a phone, npx eve remote connect --url https://<your-deployment> opens a terminal chat on the same code.

Make it yours

Everything the agent says comes from agent/instructions.md; edit it and npm run deploy. Add a tool by dropping a file in agent/tools/ (the filename is the tool name the model sees). The eve docs cover tools, state, and the Linq channel’s options.

Running more than one

Every agent you want on its own number is another clone of the blueprint with its own Linq number, its own Vercel project, and the same Agentcard credentials. Users who already stored a card unlock it with their passkey on the next agent’s link instead of entering the card again. To let anyone text the agent, not only the phone you activated with, move the Linq account off the sandbox: Upgrade in the Linq dashboard, or talk to Linq. The token and the webhook carry over.

Where to go next