API reference

Waveline API quickstart

Use the Waveline API to connect your CRM, read phone activity, keep contacts in sync, and send messages from an authorized inbox. API access must be enabled for your Waveline workspace.

Create an API key

  1. Open Settings → Integrations in Waveline and choose Add integration → API key.
  2. Give the connection a recognizable name, such as “Customer support CRM”.
  3. Select the inbox this connection should use. Workspace Owners can instead turn on Entire workspace. Grant only the permissions your application needs; for the examples below, choose Read contacts and Read inboxes.
  4. Create the key and save the one-time secret in your server's secret store.

New API keys have no expiration date. They remain usable while the connection is active and authorized. Keep a separate key for each application and environment. Never include a key in browser JavaScript, a mobile app bundle, source control, or a public URL. Replace and revoke a key if it is exposed.

Only workspace Owners can connect the entire workspace. Owners and Admins can connect a shared inbox; a workspace Member can also connect a shared inbox where they have the Manager inbox role. Any teammate can connect their own personal inbox. See access and permissions for scope and connection-lifetime details.

Make your first request

The production API base URL is https://api.waveline.tel. Every request needs an Authorization: Bearer header. The examples use WAVELINE_API_KEY, supplied through your application's secret configuration; replace placeholder IDs with values returned by your own connection.

The cURL examples use Bash-style shell syntax. On Windows, run them in Bash or adapt the environment-variable syntax to PowerShell.

curl --fail-with-body 'https://api.waveline.tel/v1/connection' \
  --header "Authorization: Bearer $WAVELINE_API_KEY"

The response's data object identifies the connection, granted scopes, and access_scope. A workspace connection can have an empty recorded inbox_ids list: use GET /v1/inboxes to retrieve its currently authorized inboxes.

curl --fail-with-body 'https://api.waveline.tel/v1/inboxes' \
  --header "Authorization: Bearer $WAVELINE_API_KEY"

If you receive an error, check the response's error.code and error.request_id. Errors and limits explains the common causes.

Read contacts with JavaScript

This example runs on a server with Node.js and built-in fetch. It reads one page and leaves contact data out of logs.

const apiKey = process.env.WAVELINE_API_KEY;
if (!apiKey) throw new Error('Configure WAVELINE_API_KEY on your server.');

const response = await fetch('https://api.waveline.tel/v1/contacts?limit=50', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const result = await response.json();
if (!response.ok) {
  throw new Error(`Waveline ${response.status}: ${result.error?.code}; request ${result.error?.request_id}`);
}

const contacts = result.data;
const nextCursor = result.next_cursor;
// Save or process contacts in your application. Keep contact IDs as strings.

For subsequent pages, put next_cursor into the cursor query parameter with URLSearchParams. Keep the key, endpoint, filters, ordering, and page size unchanged. Stop when next_cursor is null. See Pagination and filters for the options supported by each resource.

Find or update a CRM contact

Use GET /v1/contacts?phone=... or ?email=... for exact matching. URL-encode phone numbers so the leading + is preserved. For example:

curl --fail-with-body --get 'https://api.waveline.tel/v1/contacts' \
  --header "Authorization: Bearer $WAVELINE_API_KEY" \
  --data-urlencode 'phone=+12065550123'

Multiple matches are possible. Ask your application to select a specific contact rather than silently choosing the first match. Create and update operations require both contacts.read and contacts.write, plus a stable Idempotency-Key. Updates preserve the contact's audience. See the contacts reference for fields and partial-update rules.

Keep a connection in sync

For an initial import, page through accessible contacts, calls, or messages and save records by their stable IDs. Enable and durably collect webhook events before beginning the import, then reconcile those events with the imported records. Deduplicate by event ID and fetch current records when event order matters.

Pagination is a live view, not a snapshot. Creation-time filtering alone will not find later changes to older contacts. Webhooks cover supported changes; periodically reconcile records your application retains, including access changes and deletions for which there is no dedicated event.

Next steps