API Reference
Team and Access
💬Get free consultation

Team and access

ⓘ

Who can use this feature?

  • An admin on Pro or Plus can create the calling API key. These Public API routes require explicit scopes; legacy unscoped keys are refused.
  • Member writes, every API-key management route, and both AI-client routes also check that the key's creator is currently an active admin in the same shop. Member reads do not perform this additional admin check.
  • Key management checks the current Pro / Plus entitlement. Invitations and activation also enforce the shop's team plan and seat allowance.

All paths use the Public API base URL. Send X-Api-Key on every request. Send Content-Type: application/json when the table shows a JSON body, including the AI-client DELETE request. The caller's key determines the shop; a body-supplied shop ID does not switch stores.

Authority and limits

The acting admin is the member recorded when the calling key was created. The API reloads that member and requires active: true and role: "admin" in the same shop. A missing creator, a removed or inactive member, or a changed role returns 403 KEY_OWNER_NOT_ADMIN. A stored active: null does not pass this check. Possessing a management scope alone is not enough.

This check applies to POST /members, member PATCH/status/delete/resend/notification writes, all four /api-keys operations, and both /ai-clients operations. It does not apply to GET /members, GET /members/{id}, or GET /members/{id}/notifications.

OperationAdditional limit
POST /members20 invitations per hour per shop
PATCH /members/{id}/notifications30 updates per hour per calling API key
POST /api-keys10 creations per hour per shop; at most 5 active keys in the shop

The hourly limits are additional fixed-window counters. The shared Public API limits still apply: 120 requests/minute per key and 300/minute per source IP. POST /members/{id}/resend-invite uses those shared limits; it does not share the 20-invitation hourly counter. A successful invite or resend means the send operation completed, not that the recipient has opened or accepted the invitation.

Read members

All three reads take no body and return 200. Use a key created on Pro / Plus with the scope in the table. members:write implies members:read, but does not grant conversations:read for the list.

MethodPathScopeRequest exampleResponse example
GET/membersconversations:readNo body{"data":[]}
GET/members/{id}members:readid=member_123; no body{"data":{"id":"member_123","email":"[email protected]","role":"staff","active":true}}
GET/members/{id}/notificationsmembers:readid=member_123; no body{"data":{"pushTopics":[],"emailTopics":[],"forwardTopicEmails":[],"enabledSoundOpt":"first"}}

Member examples are excerpts. Member reads return the allowlisted fields id, email, firstName, lastName, fullName, avatarUrl, role, active, enableAwayMode, and createdAt when stored. Pending invitations can have active: null. They do not return passwords, authentication IDs, device tokens, or a complete permissions map. A missing or foreign member returns 404 NOT_FOUND.

Notification reads return pushTopics, emailTopics, forwardTopicEmails, enabledSoundOpt, topicEmail, and verifiedTopicEmail when stored. Device push tokens are not returned.

Invite and resend

Both routes require members:write, a key created on Pro / Plus, and the acting-admin check. Invitations require the current team entitlement or purchased additional seats and an available seat.

MethodPathJSON requestSuccess response
POST/members{"email":"[email protected]","firstName":"Example","lastName":"Teammate","permissions":{"inbox.conversations":"view"}}201 {"success":true,"id":"member_123"}
POST/members/{id}/resend-inviteNo body200 {"success":true}

email must be valid and is lowercased after validation; remove surrounding whitespace before sending. firstName and lastName are optional strings. permissions is optional and uses the catalog below. The new record is always role: "staff", with pending activation (active: null); sending role, active, or an authentication ID does not grant those fields.

Pending invitations and active human members occupy seats when inviting. The limit is the plan's seats plus purchased additional seats. The invitation link expires after 24 hours; resend to issue a new link. Reinviting an existing email through POST returns 409 MEMBER_EXISTS, including when that member is still pending. Use resend instead. Resending to an already active member returns 409 ALREADY_ACTIVE; a missing or foreign member returns 404 NOT_FOUND.

Invalid email, name types or permissions return 400 INVALID_PARAMS. Missing team entitlement returns 403 PLAN_REQUIRED; a full seat allowance returns 409 MEMBER_LIMIT_EXCEEDED. Mail failures are server failures and can occur after the pending member has been saved. Read the member list before retrying creation.

curl -X POST 'https://app.chatty.net/v1/members' \
  -H 'X-Api-Key: sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{"email":"[email protected]","firstName":"Example","lastName":"Teammate"}'

Edit, activate or remove staff

These routes require members:write, a key created on Pro / Plus, and the acting-admin check. They reject every admin target with 403 ADMIN_TARGET_FORBIDDEN, not only the last admin. The acting admin therefore cannot use them to edit, deactivate or delete themselves. Role changes and ownership transfer are not supported by these routes.

MethodPathJSON requestSuccess response
PATCH/members/{id}{"firstName":"Updated","enableAwayMode":true}200 {"success":true}
POST/members/{id}/status{"active":false}200 {"success":true}
DELETE/members/{id}No body200 {"success":true}

PATCH accepts these fields only:

FieldsAccepted values
firstName, lastName, fullName, storeAliasStrings
enabledAIResolvedReport, enabledChatPerformanceReport, enableAwayModeBooleans
unresolvedReportRecipients, performanceReportRecipientsUp to 10 valid email addresses; an array or comma-separated string. Stored as a comma-separated string
permissionsA permission map using the catalog below

Unsupported fields, including email, avatarUrl, role, and active, are ignored by profile PATCH. If no allowed field remains, it returns 400 INVALID_PARAMS. Invalid allowed values also return 400 INVALID_PARAMS. Changing names does not imply that every other name field is recomputed; send the intended fields explicitly.

The status body requires a boolean active. Activating a member rechecks the active-seat allowance and can return 409 MEMBER_LIMIT_EXCEEDED. Deactivation revokes that member's OAuth connections and Firebase sessions and disables their push delivery. It does not delete the member or their conversations.

Deletion revokes sessions before removing the staff record. It then attempts to reassign at most 500 open conversations active within the previous 30 days, or queues them for assignment when nobody is eligible. Reassignment is best effort: a failure is logged after removal and does not undo the deletion or turn it into a failed response. Do not assume all historical assignments were migrated. Missing or foreign targets return 404 NOT_FOUND.

Member permission catalog

These UI permissions are separate from API-key scopes. Only an admin may change permissions. These public staff-edit routes reject the caller and every other admin target with 403 ADMIN_TARGET_FORBIDDEN; admins retain full access. A permissions object replaces the stored map; send the full intended map. Missing entries follow the permission catalog's defaults or fallback rules, so omission does not mean none.

Allowed levelsPermission keys
none, view, editsettings.appearance, settings.availability, settings.shortcuts, settings.satisfaction, settings.reports, settings.connectedStores, settings.channels.email, settings.channels.facebook, settings.channels.whatsapp, settings.channels.integrations, settings.teamMembers, settings.billing, inbox.conversations, inbox.contacts
none, view, editai.training.knowledgeBase, ai.training.catalog, ai.training.knowledgeFiles, ai.training.shopMemory, ai.behavior.instructions, ai.behavior.skills, ai.behavior.scenarios, ai.testing, ai.settings
none, view, editticket.tickets, ticket.contacts, ticket.helpcenter, ticket.ai, ticket.improvements, ticket.automation, ticket.settings
none, editinbox.conversations.delete, inbox.contacts.export, ticket.tickets.delete, ticket.messages
none, viewticket.reports

An unknown permission key or unsupported level returns 400 INVALID_PARAMS. Retired unknown keys already present on the target may be dropped during validation instead. Assigning a member permission does not create a corresponding public API endpoint or API-key scope.

Update notification preferences

PATCH /members/{id}/notifications requires members:write, a key created on Pro / Plus, and the acting-admin check. Unlike staff profile/status/delete operations, notification preferences can target an admin, including the acting admin.

FieldMeaning
pushTopicsArray of topic strings. Supplying it for a member whose active is not true returns 409 MEMBER_INACTIVE, even for an empty array
emailTopicsArray of topic strings; may be edited for an inactive member
enabledSoundOptall, first, or none
topicEmailValid notification email address. A changed address can require email verification
forwardTopicEmailsEmail array or comma-separated string, normalized to an array. Changed values allow at most 10 valid addresses; [] clears forwards

Allowed topic names for both arrays:

conversation-assigned
new-message-assigned
conversation-mentioned
conversation-assigned-others
new-message-assigned-others
conversation-assigned-chatbot
new-message-unassigned
new-unassigned-from-ai
agent-unassigned
no-replies

Unknown topic strings are filtered out; non-string array items are rejected. pushTokens, token platform data, and verifiedTopicEmail are not writable here. Unsupported fields are ignored; if no notification field remains, the response is 400 INVALID_PARAMS. Invalid email, sound option or array types also return 400 INVALID_PARAMS.

curl -X PATCH 'https://app.chatty.net/v1/members/member_123/notifications' \
  -H 'X-Api-Key: sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{"emailTopics":["conversation-assigned"],"enabledSoundOpt":"first","topicEmail":"[email protected]"}'

Success is 200 {"success":true}. Updating topicEmail does not verify it; delivery retains the previously verified address until verification completes. The write can send a verification email and sync conversation notification settings. A missing or foreign member returns 404 NOT_FOUND.

Manage API keys

All four routes require api_keys:write, the acting-admin check, and a current Pro / Plus plan. Grant api_keys:write to the calling key through Settings → General → Manage keys; it cannot be delegated by these endpoints.

MethodPathRequestSuccess response
GET/api-keysNo body200 {"data":[]}
POST/api-keys{"title":"CRM reader","scopes":["customers:read"]}201 {"data":{"id":"key_123","title":"CRM reader","maskedKey":"sk_xxxx...xxxx","scopes":["customers:read"],"apiVersion":"2026-08-17","secret":"sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}}
PATCH/api-keys/{id}{"scopes":["customers:read"]}200 {"success":true,"id":"key_123"}
DELETE/api-keys/{id}No body200 {"success":true,"id":"key_123"}

GET lists active keys only. Its metadata fields are id, maskedKey, title, scopes, apiVersion, and createdAt when stored. It can include legacy keys, but these cannot be changed or revoked through the public routes. Use the dashboard for them.

For POST, title is a nonblank string of at most 50 characters before trimming. scopes must be an array of known scope strings when supplied; omitted scopes default to [], and duplicate scopes are removed. The new key keeps the calling key's creator identity and the current API version. Creation returns the secret once; createdAt is not included in that creation response. Store the secret immediately. GET, PATCH and DELETE cannot recover it.

The requested scopes must fit within the caller's effective access. For example, a caller with customers:write can create a key with customers:read. It cannot grant an unrelated permission. Requests containing api_keys:write return 400 INVALID_PARAMS even if the caller has that scope.

PATCH requires scopes and replaces them; it does not change the title, secret or pinned version. Before PATCH or DELETE, the target's current scopes must also fit within the caller's access. A broader target returns 403 FORBIDDEN even if the proposed replacement would be narrower. Missing, foreign, or already revoked targets return 404 NOT_FOUND; legacy targets return 403 FORBIDDEN.

!

Clearing scopes on an existing key revokes it. PATCH with {"scopes":[]} revokes the target. By contrast, POST with empty or omitted scopes creates an active key with no granted scopes. The calling key cannot PATCH or DELETE itself: both return 409 CANNOT_REVOKE_SELF.

Keys have no automatic expiry or expiry field in these requests. Revocation disables future authenticated requests while keeping the key's identity for audit records. Replacement uses create → switch the integration → revoke the old key, within the 5-active-key limit. Losing the current key-management plan returns 403 PLAN_REQUIRED; exceeding the active-key limit returns 409 KEY_LIMIT_REACHED.

List and disconnect AI clients

Both routes require members:write, a key created on Pro / Plus, and the acting-admin check. They manage existing merchant OAuth connections, not API keys or new OAuth registrations.

MethodPathRequestSuccess response
GET/ai-clientsNo body200 {"data":{"serverUrl":"https://app.chatty.net/mcp","connections":[]}}
DELETE/ai-clients{"clientId":"client_123","memberId":"member_123"}200 {"success":true}

GET groups unrevoked grants by the exact pair of client and connecting member. Each group includes clientId, clientName, clientHost, connectedByMemberId, connectedByName, createdAt, lastUsedAt, and scopes when available. scopes contains description objects (value, label, description), not bare strings. Groups combine unique scopes, the earliest creation time and latest use time. No access tokens, refresh tokens, or internal connection IDs are returned.

To disconnect, copy clientId and connectedByMemberId from one group; send the latter as body field memberId. Both must be nonblank strings. They are treated as opaque identifiers, so preserve them exactly rather than URL-normalizing, trimming or constructing them. Do not send connectedByName or an internal connection ID.

The DELETE revokes all matching active grants for that client/member pair within the calling key's shop. A valid pair with no matching grants still returns 200 {"success":true}; it is not a 404. A missing or malformed identifier returns 400 INVALID_PARAMS. Repeating the same disconnect is safe. Reconnecting requires the normal OAuth consent flow.

Shared errors

Errors from validation and guards use this shape:

{"error":{"code":"KEY_OWNER_NOT_ADMIN","message":"The API key owner must be an active shop admin"}}
HTTPCodeMeaning
400INVALID_PARAMSInvalid body, field type, permission level, delegated scope or client identifier
400INVALID_API_VERSIONInvalid version header
401UNAUTHENTICATED / INVALID_API_KEYMissing, unknown or revoked calling key
403FORBIDDENMissing route scope or target/requested key scopes exceed caller access
403KEY_OWNER_NOT_ADMINKey creator is not currently an active admin in this shop
403PLAN_REQUIREDCurrent key-management or team entitlement is missing
403ADMIN_TARGET_FORBIDDENStaff-management request targets an admin
404NOT_FOUNDMissing or foreign member/key; revoked key targets are also missing
409MEMBER_EXISTSInvite email already belongs to a member in this shop
409MEMBER_LIMIT_EXCEEDEDInvite or activation exceeds the seat allowance
409ALREADY_ACTIVEAn active member cannot receive a resend invitation through this route
409MEMBER_INACTIVEPush topics were supplied for an inactive/pending member
409KEY_LIMIT_REACHEDThe shop already has 5 active keys
409CANNOT_REVOKE_SELFPATCH/DELETE targets the calling key
429RATE_LIMITEDShared API/IP or operation-specific hourly budget exceeded

Unexpected service or mail failures may be server errors rather than this coded envelope. A write may already have saved data before a later mail or audit step fails; inspect current state before retrying. These writes record the authenticated key and acting admin, but do not provide a general idempotency key.