Authentication

Every request carries an API key. Which scopes that key holds decides not just what it can do, but which half of the API it can reach at all.

API keys

Create keys under Settings → API Keys. A key looks like wpai_<prefix>.<secret> and the full value is returned exactly once, at creation. We store only a hash, so a lost key cannot be recovered — revoke it and make another.

Keys authenticate an organization, never a person. Every query they make is scoped to that organization, which is what makes a leaked key a tenant-level problem rather than a platform-level one.

Presenting a key

The public widget surface accepts a key four ways, in this order of precedence. The private API accepts only the header.

HowExamplePrivate API
HeaderX-API-Key: wpai_abc.defYes
BearerAuthorization: Bearer wpai_abc.defNo
Body field{ "apiKey": "wpai_abc.def" }No
Query param?apiKey=wpai_abc.defNo
cURL
curl https://api.wpai.co.in/api/templates \
  -H "X-API-Key: wpai_abc123.def456..."

Avoid the query parameter

A key in a URL ends up in access logs, proxy logs and browser history. It exists for the widget, where a browser sometimes cannot set a header. Use X-API-Key everywhere you can.

Scopes

A key created without any scopes is a legacy key and keeps full access. Anything you create today should name its scopes.

ScopeGrants
chat:writeSend a message to the assistant from a website widget, and reset a session.
chat:readRead back one widget session’s conversation.
bookings:readList bookable slots for a date.
bookings:writeCreate a booking from a website form.
messages:sendServer-to-server access. See the warning below: this reaches the whole API.

A request missing a required scope returns 403 naming what was missing: API key is missing required scope: bookings:write.

Widget keys vs server keys

There are two authentication paths and the difference matters more than it looks. Scopes are checked on /api/public/*. Everywhere else, a valid key simply authenticates as an organization administrator.

A widget key is publishable

A key holding only widget scopes — chat:write, chat:read, bookings:read, bookings:write — is designed to ship in the page source of your own website. Present it on the private API and it is refused:

403
{
  "error": "This key is scoped to the website widget and can only be used on /api/public. Create a key with the messages:send scope for server-to-server calls."
}

A server key is an admin key

A key holding messages:send is not restricted to sending. On the private API it authenticates as an organization administrator — treat it with the same care as the password to your WpAi account, and keep it on your server.

Never mix the two on one key

A key holding chat:write and messages:send is not widget-only, so it is accepted on the private API. Publishing such a key in your website's JavaScript publishes organization-admin access. Keep the widget key and the server key separate.

Limits and revocation

  • An organization may hold 10 active keys. Creating an eleventh returns 403 Maximum 10 active API keys.
  • Deleting a key is a soft revoke — it stops working immediately and stays listed with a revocation date, so an audit can still see it existed.
  • Keys record a lastUsedAt stamp. It is best-effort and never fails a request, so treat it as a hint rather than an audit trail.
  • Creating and revoking keys requires an organization administrator and the api_access plan feature.
  • Requests are rate limited to 300 per minute overall. A handful of heavier calls — uploads, imports and exports — allow 20 per minute. Over either, you get 429 Too many requests, slow down.