Zyro API

Read and write your Zyro memories from your own code, automations and AI tools.

Before you start

  1. In the Zyro app, open You › Developer and turn on Cloud sync. Your memories are then stored on Zyro's server as well as your phone. Turning it off deletes the server copies and every key, connection and webhook.
  2. Create an API key. Choose Read or Read & write. The key is shown once, so copy it somewhere safe.

Quick start

curl https://api.zyro.wearsynapse.com/v1/memories?limit=5 \
  -H "Authorization: Bearer zyro_sk_..."
curl https://api.zyro.wearsynapse.com/v1/search?q=budget \
  -H "Authorization: Bearer zyro_sk_..."
curl -X POST https://api.zyro.wearsynapse.com/v1/todos \
  -H "Authorization: Bearer zyro_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"text": "Send the deck to Asha", "due": "Friday"}'

Use Zyro in AI assistants (MCP)

The MCP server is at https://api.zyro.wearsynapse.com/mcp (Streamable HTTP).

Claude and ChatGPT

Add a custom connector with the URL above. You'll see a 6-letter code: approve it in Zyro under You › Developer › Approve a sign-in. You can choose read only, and revoke the connection there at any time.

Claude Code

claude mcp add --transport http zyro https://api.zyro.wearsynapse.com/mcp \
  --header "Authorization: Bearer zyro_sk_..."

Cursor and other clients

{
  "mcpServers": {
    "zyro": {
      "url": "https://api.zyro.wearsynapse.com/mcp",
      "headers": { "Authorization": "Bearer zyro_sk_..." }
    }
  }
}

Tools

ToolArguments
search_memories{ query, limit? }
list_memories{ since?, until?, kind?, limit?, cursor? }
get_memory{ id, include_transcript? }
list_todos{ status?, limit? }
create_memory{ title, text?, kind? } (needs write access)
update_memory{ id, title?, own_notes?, append_notes? } (needs write access)
create_todo{ text, due?, memory_id? } (needs write access)
complete_todo{ id, done? } (needs write access)

REST API

Send Authorization: Bearer <API key or OAuth token>. Responses are JSON. Lists return { data, next_cursor }.

MethodPathAccessNotes
GET/v1/mereadWho the key belongs to and its scopes.
GET/v1/memoriesreadNewest first. q, kind, since, until, include=transcript, include_discarded, limit (up to 100), cursor.
GET/v1/memories/{id}readOne memory, with its transcript.
POST/v1/memorieswrite{ title, kind?, date?, transcript?, own_notes?, notes? }. Shows up in the app on the next sync.
PATCH/v1/memories/{id}writeAny of title, own_notes, notes, kind, discarded.
DELETE/v1/memories/{id}writeDeletes it here and on the phone.
GET/v1/searchreadq (required), limit (up to 20). Full-text over titles, notes and transcripts, with a snippet.
GET/v1/todosreadstatus=open|done|all (default open), limit.
POST/v1/todoswrite{ text, owner?, due?, memory_id? }. Without memory_id it goes to an Inbox memory.
PATCH/v1/todos/{id}write{ done?, text?, due?, owner? }
GET / POST/v1/webhookswriteList, or create { url, events? }. The signing secret is returned once.
PATCH / DELETE/v1/webhooks/{id}write{ url?, events?, enabled? }
POST/v1/webhooks/{id}/testwriteSends a ping event.

Memory

{
  "id": "uuid",
  "title": "Weekly sync with Asha",
  "kind": "meeting | memo | lecture | conversation",
  "status": "complete",
  "date": "2026-11-03T05:30:00Z",
  "duration_seconds": 1840,
  "source": "iphone",
  "own_notes": "",
  "notes": {
    "overview": "", "key_points": [], "decisions": [], "questions": [],
    "action_items": [{ "text": "", "owner": "", "due": "", "done": false }]
  },
  "transcript": "only on GET /v1/memories/{id} or include=transcript"
}

A to-do's id is <memory_id>:<index>, its position in the memory's action items.

Errors and limits

Errors look like { "error": { "code": "not_found", "message": "..." } }. A read-only key gets 403 insufficient_scope on writes. Each key can make 600 requests every 10 minutes; past that you get 429 with Retry-After.

Webhooks

Events: memory.created, memory.updated, memory.deleted, notes.ready, todo.created, todo.completed. Payloads never include transcripts. Failed deliveries are retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours. After 20 failures in a row the webhook is turned off.

POST <your url>
Zyro-Event: notes.ready
Zyro-Delivery: <uuid>
Zyro-Signature: t=1730612345,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>

{ "id": "...", "type": "notes.ready", "created_at": "...", "data": { "memory": { ... } } }

Checking the signature (Node)

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

OAuth

For apps acting on behalf of other people. Discovery is at https://api.zyro.wearsynapse.com/.well-known/oauth-authorization-server. Zyro supports dynamic client registration, the authorization code flow with PKCE (S256) for public clients, refresh token rotation and revocation. Scopes: memories:read, memories:write.