Guides

Server Data API

Send people, companies and events from your own backend.

Keys

Create a server key in Whazzup under Settings → Data API. The key is shown once, stored hashed and can be rotated or revoked at any time. Keep it on your server only.

Endpoints

Base URL is https://whazzup.io/api/public/data/v1. All requests need Authorization: Bearer wz_… (or X-Api-Key: wz_…).

EndpointBodyResponse
GET /whoami–{ ok, workspace: { id, name }, key: { name } }
POST /peopleexternalUserId or email (one required), name, company, attributes{ person: { id } }
GET /people/:id–{ person } by internal ID or external user ID
POST /companiesexternalId or name, plus plan, size, website, industry{ company: { id } }
POST /eventsexternalUserId or email, name, properties, pageUrl{ ok: true }

People are matched by externalUserId first, then by email; an existing person is updated, otherwise created. Attributes are simple values (string, number, boolean, null) and merge into the existing attributes. Events require a person who has visited the widget at least once; otherwise the API answers no_visitor.

Examples

People
curl -X POST https://whazzup.io/api/public/data/v1/people \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"externalUserId":"42","email":"ada@example.com","attributes":{"plan":"pro","monthlyValue":49},"company":{"externalId":"acme","name":"Acme Inc","plan":"business","size":120}}'
Events
curl -X POST https://whazzup.io/api/public/data/v1/events \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"externalUserId":"42","name":"invoice_failed","properties":{"amount":49}}'

Rate limits

  • 600 requests per minute per API key, for reads and writes separately.
  • 30 authentication attempts per minute per sender – this slows down key guessing.
  • When limited, the API answers 429 rate_limited with a Retry-After header. Wait that many seconds and retry.

Errors

identifier_required400Send externalUserId or email so the record can be matched.
insufficient_data400A new person needs at least a name, an email or one attribute.
invalid_input / invalid_json400The body is not valid JSON or fails validation.
person_not_found404No person matches the given externalUserId or email.
no_visitor409The person has never opened the widget, so events cannot be attached yet.
rate_limited429Slow down and honor the Retry-After header.
save_failed500Temporary server problem – safe to retry the same request.

Fixing 401 unauthorized

Base URL is https://whazzup.io/api/public/data/v1. Send the key as Authorization: Bearer wz_… or X-Api-Key: wz_…. Server-to-server calls are allowed from any IP; there is no origin or IP allowlist on this API. Identity verification only applies to the browser widget, never to the Data API.

A key looks like wz_XXXXXXXX_<64 hex chars> and is shown once when created. The public workspace ID used by widget.js is not a Data API key.

Check the key without writing data
curl https://whazzup.io/api/public/data/v1/whoami \
  -H "Authorization: Bearer $WHAZZUP_API_KEY"

Every 401 response carries a reason and a hint:

  • missing_credentials - No key was sent. Add the header Authorization: Bearer wz_… (or X-Api-Key).
  • malformed_key - The value is not a Data API key. Use the wz_XXXXXXXX_… key, not the public widget workspace ID.
  • unknown_key - No active key matches. The key was rotated or copied incompletely – create a new one.
  • revoked_key - The key was revoked. Create a new key under Settings → Data API.