API Key Scopes
Scoped API keys let you grant an application only the permissions it actually needs, instead of sharing a key with full account access. You can create multiple keys per organisation, label them per app, revoke them individually, and track when each key was last used.
Principle of Least Privilege
contacts:write + config:read — if the key ever leaks, the blast radius is two permissions, not your whole account.Key Types
- Scoped keys (recommended) — start with
sk_, carry an explicit list of scopes, and are stored hashed. The full key is shown exactly once at creation. - Legacy key — the original single full-access key (64-character hex, no prefix). Existing legacy keys keep working unchanged with full access, but the legacy key is planned for deprecation — migrate integrations to scoped keys.
Both key types authenticate the same way — as a Bearer token (see Authentication). Nothing about the request format changes.
Creating a Scoped Key
- Open your Sendiee Dashboard → API & Webhooks
- In Scoped API Keys, click Create key
- Give it a label and tick only the scopes the app needs
- Copy or download the key immediately — it is shown only once and stored hashed on our side
Up to 10 active scoped keys can exist per organisation. Revoking a key takes effect immediately.
Scope Reference
Scope names follow the resource:action pattern and map to the corresponding resource paths under /v2.0. Selecting Full access (*) makes the key equivalent to a legacy key.
| Scope | Grants access to |
|---|---|
| contacts:read | List contacts, advanced filtering, look up a contact by phone |
| contacts:write | Create or update contacts (including custom fields and lead category) |
| config:read | Read contact field schema, custom attribute definitions, tags, and the full lead-segmentation config (categories, follow-ups, and AI insights) |
| config:write | Create, update, and delete custom attributes and tags, and manage lead segmentation (settings, categories, follow-ups, and AI insights) |
| messages:send | Send template and freeform messages (WhatsApp + WebWhatsApp), cancel scheduled messages |
| messages:read | Check message status, list scheduled messages |
| chats:read | Read conversation history and chat lists |
| templates:read | List message templates and fetch a single template by id |
| templates:write | Create and submit message templates |
| campaigns:read | List campaigns, fetch reports, preview audiences |
| campaigns:write | Create and cancel campaigns |
| assistants:read | List AI assistants, configurations, and version history |
| assistants:write | Create, update, toggle, restore, and delete AI assistants |
| tools:read | List AI tools, schemas, version history, and run logs |
| tools:write | Create, update, toggle, restore, and delete AI tools |
| catalogs:read | List catalogs, products, collections, and sync status |
| catalogs:write | Manage catalogs, products, collections, sources, channels, and syncs |
| channels:read | Check channel connection status (WhatsApp, Instagram, Messenger) |
| insights:read | Read daily summaries and lead-pipeline snapshots |
| billing:read | Read plan, subscriptions, payments, and wallet balance |
| integrations:shopify | All Shopify data and order endpoints (REST + GraphQL lanes) |
| integrations:zoho | All Zoho CRM, Inventory, and Desk endpoints |
Read vs Write via POST
POST for body-based queries — POST /v2.0/contacts/filter, POST /v2.0/contacts/phone, POST /v2.0/campaigns/preview, and product search. These require the :read scope of their resource, not :write.Using a Scoped Key
A scoped key is used exactly like any other key. With a key holding contacts:write + config:read:
# Allowed: contacts:write
curl -X POST https://api.sendiee.com/v2.0/contacts \
-H "Authorization: Bearer sk_YOUR_SCOPED_KEY" \
-H "Content-Type: application/json" \
-d '{"phone": "+15551234567", "contactName": "Ada Lovelace"}'
# Allowed: config:read
curl -X GET https://api.sendiee.com/v2.0/leads/categories \
-H "Authorization: Bearer sk_YOUR_SCOPED_KEY"
# Denied: requires messages:send -> 403 INSUFFICIENT_SCOPE
curl -X POST https://api.sendiee.com/v2.0/whatsapp/send \
-H "Authorization: Bearer sk_YOUR_SCOPED_KEY" \
-H "Content-Type: application/json" \
-d '{"brandNumber": "15550001111", "toPhoneNumber": "+15551234567", "templateName": "hello"}'The INSUFFICIENT_SCOPE Error
When a scoped key calls an endpoint outside its scopes, the API responds with 403 and names the missing scope so you can fix the key instead of guessing:
{
"error": true,
"code": "INSUFFICIENT_SCOPE",
"required_scope": "messages:send",
"message": "This API key does not have the required scope 'messages:send'."
}Scoped keys are default-deny: endpoints not covered by any granted scope are rejected. Legacy and full-access keys are never affected by scope checks.
Security Model
- Hashed at rest — scoped keys are stored as SHA-256 hashes; Sendiee cannot show you the key again after creation
- Instant revocation — revoked keys fail with
401 INVALID_API_KEYon the next request - Last-used tracking — the dashboard shows when each key last made a request, so stale keys are easy to spot and revoke
- Per-key rate limiting — each key gets its own counters at your plan limits, so one runaway integration cannot starve the others (see Rate Limits)
- Per-key request logs— the dashboard's Logs tab can filter API requests by key
Legacy Key Deprecation