Text your agent in 10 minutes

Create an agent in the nmbr app, then make it talk back from a terminal — with curl or the TypeScript SDK.

You need: the nmbr app (iOS, Android or web), and a machine with outbound internet — a laptop is fine, nothing has to be reachable from the internet.

1. Create the agent (in the app) Available

Agents → Yours → Create an agent. Give it a name. nmbr assigns a random 800-xxx-xxx nmbr, adds you as its first contact, and shows its token once. Copy it: it starts with agent:.

export TOKEN="agent:…"

Lost it? Open the agent (Agents → Yours → your agent) and mint a new token; revoke the old one there too.

2. Say hello to yourself

curl -s https://nmbr.ai/api/agent/v1/me -H "Authorization: Bearer $TOKEN"
# {"id":"…","nmbr":"800-123-456","displayName":"My Agent",…}

curl -s -X POST https://nmbr.ai/api/agent/v1/messages \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"to":"123-456-789","type":"text","content":"hello from my laptop"}'

Replace 123-456-789 with your own nmbr. Your phone buzzes. Reply to it in the app.

3. Receive the reply (long-poll)

SEQ=$(curl -s https://nmbr.ai/api/agent/v1/updates/cursor -H "Authorization: Bearer $TOKEN" | jq .seq)
curl -s "https://nmbr.ai/api/agent/v1/updates?afterSeq=$SEQ&wait=25" -H "Authorization: Bearer $TOKEN"

The request holds up to 25 s and returns as soon as something happens:

{ "events": [ { "id": "…", "seq": 42, "type": "message.received", "ts": "…", "agentId": "…",
    "payload": { "conversationId": "…", "from": { "nmbr": "123-456-789", "displayName": "You" },
                 "message": { "id": "…", "type": "text", "content": "hi!" } } } ],
  "nextSeq": 42 }

Loop with afterSeq=nextSeq. That's the whole inbound story — no webhook, no tunnel.

4. An echo agent with the SDK Available

npm i @nmbrai/sdk
import { NmbrAgent } from "@nmbrai/sdk";

const agent = new NmbrAgent({ token: process.env.TOKEN! });

for await (const event of agent.updates()) {          // long-polls forever, resumes after errors
  if (event.type === "message.received") {
    const { conversationId, message } = event.payload as any;
    await agent.setTyping(conversationId);
    await agent.sendText({ conversationId }, `You said: ${message.content}`);
  }
}

Run it with node --env-file=.env echo.mjs (Node ≥ 18). Text your agent. It answers.

Swap the echo for an LLM call and you have a personal assistant on your phone that runs on your hardware. Voice notes arrive with message.transcript already filled in.

5. Ask before acting Available

const decision = await agent.proposeAndWait({
  to: "123-456-789",
  kind: "deploy",
  title: "Deploy v2 to prod?",
  payload: { ref: "abc123" },
});
if (decision.state === "approved") deploy(decision.editedPayload ?? decision.payload);
// "rejected" and "expired" both mean: do not act.

Your phone shows an approval card with Approve / Edit / Reject. Nothing runs on nmbr's side — ever. See Approvals.

Next