NeuSynapseAPI 2026-11-13
neusynapse.com

Partner API

Show a NeuSynapse account inside your platform

NeuSynapse runs AI agents that answer a business's calls, forms, WhatsApp and website chat, qualify the person, book appointments and write a summary on the lead's card. This API lets your platform see that work: the account's status, its leads and what the AI wrote about them. To change anything, the user opens NeuSynapse with the link that comes with every lead.

Overview

PieceWhat it does
Read APIFour GET endpoints with a per-account API key: account status, leads, one lead with its summaries.
WebhooksWe POST a signed event to your URL when a lead is created or changes, a call is summarized, an appointment is booked or a form arrives.
Deep linksEvery lead carries url, which opens it in NeuSynapse. It asks the user to log in — the link alone shows nothing.

The API is read-only by design. No key can send messages, place calls, change the agent, read conversations, recordings or transcripts, or see another account. Notes a person writes by hand in NeuSynapse are never shared.

Getting access

Each NeuSynapse account owner creates a key in Settings → Integrations (API) and gives it to you. One key gives access to exactly one account. The owner chooses what it can see and can remove its access at any time — it stops working immediately.

ScopeAllows
status:readGET /status
leads:readGET /leads, GET /leads/{id}

Keys look like nsk_live_<12 characters>_<43 characters>. We only store a hash: if one is lost, the owner creates a new one.

Authentication

Send the key in the Authorization header of every request. Base URL:

https://zvwbauwimsrntekwinvh.supabase.co/functions/v1/partner-api/v1
curl
curl https://zvwbauwimsrntekwinvh.supabase.co/functions/v1/partner-api/v1/status \
  -H "Authorization: Bearer nsk_live_xxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Call the API from your servers only. Keys are secrets: never put them in a browser, a mobile app or a URL. The API sends no CORS headers, so browsers can't call it directly. Responses carry Cache-Control: no-store.

Errors

Errors use HTTP status codes and a JSON body:

{ "error": { "code": "insufficient_scope", "message": "This key doesn't have the leads:read scope." } }
StatuscodeMeaning
400invalid_parameterA query parameter is not valid.
401invalid_api_keyMissing, malformed, unknown or revoked key (same answer for all four).
403insufficient_scopeThe key doesn't have the scope this endpoint needs.
403account_inactiveThe NeuSynapse account is suspended or cancelled.
403not_in_planThe account's plan doesn't include integrations.
404not_foundUnknown endpoint, or a lead that doesn't exist in this account.
405method_not_allowedOnly GET is accepted.
429rate_limitedToo many requests. Wait the seconds in Retry-After.
500 / 503internal_errorOur side. Retry with backoff (unavailable comes with Retry-After).

Rate limits

120 requests per minute per key and 300 per minute per IP address. Over that, the answer is 429 with Retry-After. Prefer webhooks over polling.

GET /me

GET/meany key

Which account and key you are using. Useful to check a key when the user pastes it.

Response
{
  "account_id": "1f4e…",
  "key": { "name": "Realeflow", "prefix": "ab12cd34ef56", "scopes": ["status:read", "leads:read"], "created_at": "2026-11-13T15:02:11.000Z" }
}

GET /status

GET/status?days=7status:read

A summary for a dashboard widget. days: 1–30, default 7.

Response
{
  "account_id": "1f4e…",
  "agents": { "total": 2, "answering": 1 },
  "period": { "from": "2026-11-06T00:00:00.000Z", "to": "2026-11-13T00:00:00.000Z", "days": 7 },
  "counts": {
    "leads_new": 38,
    "calls_summarized": 52,
    "appointments_booked": 6,
    "forms_submitted": 14,
    "hot_leads": 11
  },
  "recent_leads": [ …up to 10 lead objects, most recently updated first… ],
  "links": {
    "dashboard": "https://app.neusynapse.com/dashboard",
    "pipeline": "https://app.neusynapse.com/dashboard/crm/pipeline"
  }
}

hot_leads is the current number of active leads marked hot, not limited to the period.

GET /leads

GET/leads?updated_since=&limit=&cursor=&include_archived=leads:read
ParameterDescription
updated_sinceISO 8601 date or date-time. Only leads changed at or after it.
limit1–100, default 50.
cursorThe next_cursor of the previous page, exactly as it came.
include_archivedtrue to include leads removed from the Pipeline (archived: true). Default false.

Leads come oldest change first. Follow next_cursor until it is null. To sync, store the newest updated_at you saw and ask again with updated_since a few minutes earlier, deduplicating by id.

Response
{ "data": [ …lead objects… ], "next_cursor": "eyJ1IjoiMjAyNi0xMS0xM1Qw…" }

GET /leads/{id}

GET/leads/{id}leads:read

One lead plus its last 20 automatic notes (newest first): AI call summaries, calls made from the NeuSynapse portal, appointments and forms.

Response
{
  …lead object…,
  "notes": [
    { "id": "…", "type": "call", "created_at": "…", "call": { "handled_by": "ai", "direction": "inbound", "duration_seconds": 252, "summary": "…" } },
    { "id": "…", "type": "appointment", "created_at": "…", "appointment": { "starts_at": "2026-11-14T15:00:00.000Z", "timezone": "America/New_York", "services": ["Property visit"], "attendant": "Ana", "channel": "voice" } },
    { "id": "…", "type": "form", "created_at": "…", "form": { "name": "Sell your house fast", "page_url": "https://example.com/sell", "fields": [{ "label": "Property address", "value": "2218 Pine Hollow Dr" }] } }
  ]
}

The lead object

{
  "id": "6f1c2a1e-6c1f-4f2b-9d77-2b7f0f1f9a10",
  "name": "Margaret Collins",
  "phone": "+14075550142",
  "email": null,
  "stage": { "name": "Qualified", "kind": "open" },
  "temperature": "hot",
  "source": "ai_call",
  "archived": false,
  "created_at": "2026-11-12T20:41:07.512Z",
  "updated_at": "2026-11-13T01:47:00.000Z",
  "stage_changed_at": "2026-11-13T01:47:00.000Z",
  "url": "https://app.neusynapse.com/dashboard/crm/pipeline?card=6f1c2a1e-6c1f-4f2b-9d77-2b7f0f1f9a10"
}
FieldTypeNotes
iduuidStable. Use it to match the lead in your system.
namestring | nullUp to 120 characters.
phonestring | nullE.164, e.g. +14075550142.
emailstring | null
stageobject | nullname as the account named it; kind: open, won or lost.
temperaturestring | nullhot, warm or cold.
sourcestringHow it arrived: ai_call, portal_call, form, whatsapp, instagram, messenger, sms, web, appointment, manual (or other).
archivedbooleanRemoved from the Pipeline.
created_at / updated_at / stage_changed_atISO 8601UTC.
urlstringOpens the lead in NeuSynapse (login required).

New fields may be added at any time. Ignore the ones you don't know.

Webhooks

The account owner adds your URL in Settings → Integrations (API), picks the events and receives a signing secret (whsec_…), shown once — they give it to you. Each account can have up to 3 webhook URLs.

  • Your URL must be https on port 443 and resolve to a public address.
  • Answer with any 2xx within 10 seconds. Do the work afterwards.
  • Redirects are not followed (a 3xx counts as a failure). We read at most 4 KB of your answer and never store it.
HeaderValue
NeuSynapse-Signaturet=<unix seconds>,v1=<hex HMAC-SHA256> — see below.
NeuSynapse-Event-IdSame as the body's id. Unique per event; retries reuse it.
NeuSynapse-Event-Typee.g. call.summarized.
NeuSynapse-Delivery-Attempt1, 2, 3…
Content-Typeapplication/json
Example: call.summarized
{
  "id": "0b6f3c8e-2f0e-4a51-8c55-7f3b8f6f4f21",
  "type": "call.summarized",
  "api_version": "2026-11-13",
  "created_at": "2026-11-13T01:47:00.000Z",
  "account_id": "1f4e…",
  "data": {
    "lead": { …the lead object… },
    "note_id": "c2a9…",
    "call": {
      "handled_by": "ai",
      "direction": "inbound",
      "duration_seconds": 252,
      "ended_at": "2026-11-13T01:46:41.000Z",
      "summary": "Inherited the house, lives out of state, wants to sell within 30 days…",
      "campaign": null,
      "temperature": null,
      "next_step": null
    }
  }
}

Event types

typeWhendata
lead.createdA person is added to the account's Pipeline (AI marked them interested, a form, an appointment, or by hand).lead
lead.updatedStage, temperature or archived changed.lead, changes e.g. {"stage":{"from":"New","to":"Qualified"}}
call.summarizedAn AI call (or a call made from the NeuSynapse portal) ended with a summary.lead, note_id, call
appointment.bookedAn appointment was booked for the lead.lead, note_id, appointment
form.submittedThe lead sent a NeuSynapse form.lead, note_id, form
pingThe owner pressed “Test” in NeuSynapse.message

data.lead is the lead object as it was when the event was sent. call, appointment and form have the same shape as the notes of GET /leads/{id}.

Verifying signatures

Always verify before trusting an event. Compute HMAC-SHA256 of <t>.<raw body> with the signing secret and compare it with v1in constant time. Reject events whose tis more than 5 minutes away from your clock. Use the raw body — re-serialized JSON won't match.

Node.js
import crypto from "node:crypto";

// rawBody: the request body EXACTLY as received (a string or Buffer), before JSON.parse.
export function verifyNeuSynapse(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    String(header || "").split(",").map((p) => p.split("=").map((s) => s.trim()))
  );
  const t = Number(parts.t);
  if (!Number.isInteger(t) || !parts.v1) return false;
  if (Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false; // replay protection
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(parts.v1, "hex");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Python
import hmac, hashlib, time

def verify_neusynapse(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(p.strip().split("=", 1) for p in (header or "").split(",") if "=" in p)
    try:
        t = int(parts["t"])
    except (KeyError, ValueError):
        return False
    if abs(time.time() - t) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

When the owner creates a new secret in NeuSynapse, the old one stops working immediately.

Delivery and retries

Events are sent within about a minute. A failed delivery (no answer in 10 s, network error, 3xx, 4xx or 5xx) is retried after 1 min, 5 min, 15 min, 1 h, 3 h, 6 h and 12 h — 8 attempts over about a day — then dropped.

  • Delivery is at least once: the same event can arrive twice. Deduplicate by id.
  • Order is not guaranteed. Use created_at and the lead's updated_at, or fetch the lead with GET /leads/{id}.
  • After 20 failures in a row with no success in 24 hours, the webhook is switched off and the owner is notified in NeuSynapse. They turn it back on there.

Security notes

  • Store keys and signing secrets like passwords (a secrets manager or encrypted at rest). Use a separate key for each environment.
  • Form answers, names and summaries contain text written by members of the public. Escape them before showing them in HTML; never run them as code or queries.
  • The data is personal information of the account's customers. Use it only to show it to that account's users, and delete it when the account disconnects.
  • Found a security issue? Write to contact@neusynapse.com.

Versioning

Current version: 2026-11-13 (header NeuSynapse-Api-Version, and api_version in every event). We may add endpoints, fields and event types without notice. Removing or changing an existing field means a new version, announced in advance.

Questions: contact@neusynapse.com.