Developers

Build on Neural Summary

Send calls and meetings in over a REST API. Get the summary, action items, and any Lens you ask for back as signed webhooks. No new tool for your team, no copy-paste.

Available on the Enterprise plan

How it works

You push a recording with optional metadata. Neural Summary transcribes it, writes the summary, and generates the Lens outputs you requested. When it is done, we send a signed webhook to your endpoint. From there you route the result anywhere: a CRM, an inbox, a database, or an automation in Zapier, Make, or n8n.

One recording in, structured outputs out.

Quick start

1. Create an API key. Open Settings › Integrations and copy the key. It is shown once.

# Create an API key in Settings > Integrations. It is shown once.
API_KEY="ns_live_..."

2. Upload an audio file. Multipart is fine for small files.

curl -X POST https://neuralsummary.com/integrations/v1/transcriptions \
  -H "Authorization: Bearer $API_KEY" \
  -F "audio=@./call.mp3;type=audio/mpeg" \
  -F 'metadata={"title":"Call with Acme","callMetadata":{"callerName":"Jane Doe","callerEmail":"jane@acme.com"},"integrationOptions":{"lensTemplates":["followUpEmail"]}}'

3. Receive the result. Subscribe a webhook (recommended) or poll the transcription until it is complete.

curl -H "Authorization: Bearer $API_KEY" \
  https://neuralsummary.com/integrations/v1/transcriptions/<id>

Authentication

Every /integrations/v1/* request needs an API key, in either header:

  • Authorization: Bearer ns_live_...
  • x-api-key: ns_live_...

Keys are managed at Settings › Integrations. We store a bcrypt hash plus the first characters for display, never the raw key. Revoke any key from the same screen and it stops working immediately. A key inherits its owner’s plan limits, and integration uploads count against the same monthly quota as the app.

Endpoints

POST/integrations/v1/transcriptions

Multipart upload, suitable for files up to about 100 MB. Send the file as audio and an optional JSON metadata field with title, callMetadata, and integrationOptions. Returns a transcription with status pending.

POST/integrations/v1/upload-url

For large recordings. Ask for a signed storage URL, upload the file directly to it, then call from-storage. The audio never passes through our API.

{
  "fileName": "long-call.m4a",
  "contentType": "audio/x-m4a",
  "fileSize": 524288000
}

You receive an uploadUrl and a storagePath. PUT the bytes with the exact same Content-Type. The URL expires in one hour.

POST/integrations/v1/transcriptions/from-storage

After the PUT completes, tell us the file is ready. We only accept a storagePath we issued.

{
  "storagePath": "uploads/<your-uid>/...long-call.m4a",
  "fileName": "long-call.m4a",
  "fileSize": 524288000,
  "contentType": "audio/x-m4a",
  "title": "Sales call with Acme",
  "callMetadata": { "callerEmail": "jane@acme.com" },
  "integrationOptions": { "lensTemplates": ["followUpEmail", "salesEmail"] }
}
GET/integrations/v1/transcriptions/:id

Polling fallback for callers that cannot receive webhooks. Returns the full transcription, populated with results once status is completed. Poll no faster than once every 10 seconds. Typical latency is 30 to 60 seconds per recording minute.

Lens templates

Pass any of these IDs to integrationOptions.lensTemplates to have them generated alongside the summary. The summary is always produced. Unknown IDs return 400 Bad Request.

IDOutput
followUpEmailReady-to-send follow-up email
salesEmailSales follow-up email with proof points
actionItemsOwners-and-dates action list
meetingMinutesFormal meeting minutes
oneOnOneNotes1:1 notes
agileBacklogUser stories with acceptance criteria
prdProduct requirements doc
retrospectiveRetro themes and improvements
crmNotesCRM-shaped notes (BANT, stakeholders)
dealQualificationMEDDICC qualification
objectionHandlerObjections and suggested responses
blogPostDrafted blog post
linkedinPostLinkedIn post variants

Webhooks

Add an endpoint at Settings › Integrations › Webhooks. We send a signed POST when an integration-sourced transcription finishes. Subscribe to either or both events: v1.transcription.completed and v1.transcription.failed.

Delivery is retried on any non-2xx response.

Payload

{
  "id": "evt_aBcDeFgHiJkLmNoP",
  "event": "v1.transcription.completed",
  "createdAt": "2026-05-16T10:13:45.123Z",
  "data": {
    "transcriptionId": "tr_xyz",
    "title": "Call with Acme",
    "durationSeconds": 312,
    "detectedLanguage": "english",
    "callMetadata": {
      "callerName": "Jane Doe",
      "callerEmail": "jane@acme.com",
      "callerPhone": "+31612345678",
      "callSource": "ringcentral",
      "externalRef": "call_98765"
    },
    "summary": { "...": "SummaryV2: title, intro, sections, decisions, nextSteps" },
    "generatedAnalysisIds": ["ana_abc", "ana_def"],
    "conversationCategory": "sales-call",
    "completedAt": "2026-05-16T10:13:45.000Z"
  }
}

Verify the signature

The X-NeuralSummary-Signature header is t=<unix-seconds>,v1=<hex>. The HMAC is SHA-256 of <seconds>.<raw-body> with your webhook secret. This mirrors Stripe’s format. Reject anything older than five minutes.

const crypto = require('crypto');

// Header format: t=<unix-seconds>,v1=<hex-hmac>
function verify(rawBody, headerValue, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    headerValue.split(',').map((p) => p.split('=')),
  );
  const ts = parseInt(parts.t, 10);
  if (Math.abs(Date.now() / 1000 - ts) > toleranceSeconds) return false;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${ts}.${rawBody}`)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(parts.v1, 'hex'),
  );
}

Retries

A non-2xx response is retried up to five times with exponential backoff: 30s, 1m, 2m, 4m, 8m. We do not retry 4xx responses other than 408 and 429. Failed deliveries appear under Recent deliveries with a one-click Replay.

Zapier, Make, and n8n

You do not need to write a webhook handler. Zapier, Make, and n8n all have a generic HTTP action that calls our endpoints, plus a catch-hook trigger that receives our webhook. A typical recipe turns a recorded call into a drafted follow-up email:

Call recording to follow-up draft, with no code.

The shape is the same in each tool: use the HTTP module/action for the three upload calls, and the catch-hook trigger for the webhook. Take data.callMetadata.callerEmail from the webhook as the recipient, and fetch the Lens body with the polling endpoint using data.transcriptionId.

Limits and security

  • Enterprise plan required (admins bypass for testing).
  • Rate limits per key: 30 multipart uploads, 60 upload-URL mints, and 120 polling reads per minute.
  • Up to 5 GB per file, matching the Enterprise upload limit.
  • Webhook URLs must use HTTPS in production. Loopback hosts are rejected.
  • API keys are bcrypt-hashed at rest. Webhook secrets are shown on demand; treat them like a password.

Start building

Generate an API key in Settings › Integrations and send your first recording. Need a hand? hello@neuralsummary.com.

Ontwikkelaars — Neural Summary API en webhooks