Build on the conversations that move work forward.
Turn Wave sessions into searchable product context, automations, agent memory, and live workflows—with clean JSON and scopes you control.
curl -H 'Authorization: Bearer $WAVE_API_KEY' \
https://api.wave.co/v1/sessions?limit=2{
"sessions": [{
"id": "sess_01J...",
"title": "Product review",
"type": "meeting"
}],
"has_more": true
}https://api.wave.co/v1Search
Semantic recall
Find the moment, not just the meeting.
Shape
Structured data
Sessions, transcripts, folders, and actions.
React
Live events
Cursor feeds and signed webhooks.
Start here
Make your first request in minutes.
Create a scoped token, send it as a Bearer credential, and get back predictable JSON.
1. Get an API token
Create a token at app.wave.co/settings/integrations/api. Choose the scopes your application needs.
2. Make your first request
Include your token in the Authorization header:
curl -H "Authorization: Bearer wave_api_xxx..." \ https://api.wave.co/v1/sessions
3. Handle the response
All responses are JSON. Successful responses return the data directly:
{
"sessions": [
{
"id": "abc123",
"title": "Weekly Standup",
"timestamp": "2025-01-20T10:00:00Z",
"duration_seconds": 1800,
"type": "meeting",
"platform": "zoom"
}
],
"next_cursor": "2025-01-19T09:00:00Z",
"has_more": true
}Sessions of type phone also include a phone object with the call direction (inbound / outbound), to_number, from_number, status, and an ongoing flag for live calls. Inbound calls are bridge connections, so the other party is unknown — to_number is your verified caller ID and from_number is null.
Access control
Authentication
All API requests must be authenticated using a Bearer token in the Authorization header.
Creating a Token
- Go to app.wave.co/settings/integrations/api
- Click "Create Token" and give it a descriptive name
- Select the permissions (scopes) your application needs
- Copy the token immediately — it will only be shown once
Scopes
Tokens are granted specific permissions that control what data they can access. Request only the scopes your application actually needs.
List sessions and retrieve session metadata including titles, timestamps, summaries, and notes. Also allows access to session statistics and bulk export.
Required for: GET /v1/sessions, GET /v1/sessions/:id, GET /v1/sessions/stats, POST /v1/sessions/bulk
Update session metadata including title, notes, tags, favorite status, and structured action items. Lets agents write back action items extracted from a session so users can edit them and the agent can re-read the edits — a closed loop.
Required for: PATCH /v1/sessions/:id
Create folders and add or remove sessions from folders. Folders are non-exclusive — a session can sit in many folders at once (Gmail-labels model, not Finder-folders).
Required for: POST /v1/folders, POST /v1/sessions/:id/folders/:folderId, DELETE /v1/sessions/:id/folders/:folderId
Pull and acknowledge events from the per-token cursor feed. An alternative to running a webhook receiver — Wave keeps your cursor server-side so you never have to track “did I already process this event?” yourself.
Required for: GET /v1/events, POST /v1/events/ack
Permanently delete sessions. Storage files are cleaned up asynchronously.
Required for: DELETE /v1/sessions/:id
Perform semantic search across all your sessions using natural language queries.
Required for: POST /v1/sessions/search
Access full session transcripts with speaker attribution and timestamps. Also required when requesting transcripts in bulk exports.
Required for: GET /v1/sessions/:id/transcript
Access signed URLs for session audio and video files. URLs expire after 1 hour.
Required for: GET /v1/sessions/:id/media
Read account information including subscription status and total session count.
Required for: GET /v1/account
Create, list, update, delete, and test webhook endpoints. Manage signing secrets.
Required for: All /v1/webhooks/* endpoints
Token Security
- Tokens are only shown once when created — store them securely
- Tokens expire after 1 year but can be revoked at any time
- Use environment variables to store tokens, never commit them to code
- Create separate tokens for different applications
- Revoke tokens immediately if they may have been compromised
- Grant only the scopes your application needs (principle of least privilege)
Error Responses
Authentication errors return appropriate HTTP status codes:
Missing or malformed Authorization header
{
"error": {
"code": "unauthorized",
"message": "Missing or invalid Authorization header"
}
}Token is invalid, expired, or has been revoked
{
"error": {
"code": "invalid_token",
"message": "Token is invalid, expired, or revoked"
}
}Token does not have the required scope for this endpoint
{
"error": {
"code": "insufficient_scope",
"message": "This endpoint requires the 'sessions:write' scope"
}
}Build surface
API Endpoints
Quick reference for all Wave API endpoints. For request/response schemas and a built-in request builder, see the Interactive API Reference.
All endpoints require a Bearer token. Base URL: https://api.wave.co
Sessions
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /v1/sessions | sessions:read | List sessions with cursor-based pagination |
| GET | /v1/sessions/:id | sessions:read | Get session details (metadata, summary, notes, tags) |
| PATCH | /v1/sessions/:id | sessions:write | Update title, notes, tags, favorite, or structured action_items (supports If-Match for optimistic concurrency) |
| GET | /v1/sessions/:id/action-items | sessions:read | Read structured action items + current version (pass as If-Match on PATCH) |
| GET | /v1/sessions?tag=<name> | sessions:read | Filter by tag (exact, case-sensitive). Repeatable or comma-separated; pair with tag_mode=all to require every tag. |
| DELETE | /v1/sessions/:id | sessions:delete | Permanently delete a session |
| POST | /v1/sessions/search | sessions:search | Semantic search across all sessions |
| GET | /v1/sessions/stats | sessions:read | Aggregated session statistics for a date range |
| POST | /v1/sessions/bulk | sessions:read | Bulk export up to 50 sessions by ID (set include_transcript: true for full transcripts) |
Folders
Folders are non-exclusive — a session can live in many folders at once. Pair GET /v1/folders with GET /v1/sessions?folder=… to scope results, or use the membership endpoints to organize sessions programmatically.
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /v1/folders | sessions:read | List the user's folders (id, name, color, session count) |
| POST | /v1/folders | folders:write | Create a folder (name collisions return the existing folder — safe to retry) |
| POST | /v1/sessions/:id/folders/:folderId | folders:write | Add a session to a folder (non-exclusive; idempotent) |
| DELETE | /v1/sessions/:id/folders/:folderId | folders:write | Remove a session from a folder |
| GET | /v1/sessions?folder=<id|name> | sessions:read | Filter the sessions list to one folder (accepts folder id or case-insensitive name) |
Event Feed
Stripe-style per-token cursor. Wave keeps track of where you are in the event stream on the server, so you don't have to maintain dedupe state on the client. Use instead of — or alongside — webhooks. Same event shapes, same ids.
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /v1/events | events:read | Pull events since the last ack (or a passed cursor). Includes next_cursor + has_more. |
| POST | /v1/events/ack | events:read | Advance the cursor (monotonic). Later polls skip events at or before this cursor. |
Transcripts
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /v1/sessions/:id/transcript | transcripts:read | Full transcript with optional speaker segments |
Media
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /v1/sessions/:id/media | media:read | Signed audio/video URLs (expire after 1 hour) |
Account
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /v1/account | account:read | User profile, subscription status, and session count |
Reactive workflows
Webhooks
Register HTTPS endpoints to receive real-time notifications when sessions are completed, updated, or deleted. Payloads are signed with HMAC-SHA256 for verification.
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /v1/webhooks | webhooks:manage | List all registered webhooks |
| POST | /v1/webhooks | webhooks:manage | Register a new webhook (returns signing secret) |
| PATCH | /v1/webhooks/:id | webhooks:manage | Update URL, events, or active status |
| DELETE | /v1/webhooks/:id | webhooks:manage | Delete a webhook |
| POST | /v1/webhooks/:id/rotate-secret | webhooks:manage | Regenerate the signing secret |
| POST | /v1/webhooks/:id/test | webhooks:manage | Send a test event and report delivery status |
Webhook Events
| Event | Triggered When |
|---|---|
| session.completed | Fires once, after a session finishes processing and the summary, notes, and tags are queryable. This is the “session is ready to use” event. |
| session.updated | Session metadata was changed (title, summary, notes, tags, favorite). Fires for edits from any source — the API, mobile app, or web app. |
| session.action_items.updated | Structured action items on a session were written or edited via PATCH. Carries the full session in data.session, including the new action_items and action_items_version. |
| session.deleted | Session was deleted (soft-delete or hard-delete of a completed session) |
Signature Verification
Each delivery includes these headers for verification:
| Header | Description |
|---|---|
| X-Wave-Webhook-Id | Unique event ID |
| X-Wave-Webhook-Timestamp | Unix timestamp of the delivery |
| X-Wave-Webhook-Signature | HMAC-SHA256 signature |
To verify: compute HMAC-SHA256(secret, "webhookId.timestamp.body") and compare with the signature header.
Predictable failures
Error Codes
All errors return a consistent JSON structure:
{
"error": {
"code": "error_code",
"message": "Human-readable description"
}
}| Code | Status | Description |
|---|---|---|
| invalid_request | 400 | Missing or invalid parameters |
| unauthorized | 401 | Missing or invalid Authorization header |
| invalid_token | 401 | Token is invalid, expired, or revoked |
| insufficient_scope | 403 | Token lacks required permission |
| not_found | 404 | Resource not found |
| limit_exceeded | 400 | Resource limit reached (e.g. max webhooks) |
| rate_limit_exceeded | 429 | Too many requests |
| internal_error | 500 | Server error |
Usage guardrails
Rate Limits
- 60 requests per minute per token
- 10,000 requests per day per token
Rate limit info is included in every response:
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 58 X-RateLimit-Reset: 1706000000
Machine-readable contract
API Reference
The full OpenAPI 3.1 specification is available at:
Use it to generate client libraries, import into Postman, or validate requests.
Want to try these endpoints? Open the Interactive API Reference for a built-in request builder with live responses.