Specala AIDocs
API Reference

Members & identifiers

GET /workspace/members and PUT/DELETE /workspace/members/{user_id}/identities — list workspace members and link your CRM or telephony identifiers to them.

For integrations that know people by their own ids

A CRM knows a manager as user 12345; a PBX knows them as extension 101. Link those identifiers to workspace members once, and every upload can name the author as X-Author: external:hubspot:12345 — no mapping table on your side. See Assigning an author.

Owners only

These endpoints need a key created with Allow managing members, and only a workspace owner can create such a key — the member list contains emails, and linking identifiers decides who receives whose calls. Other keys get 403 members_scope_required. See Authentication → Key permissions.

Workspace owners can also manage the same identifiers in the app: Settings → Members → External identifiers next to each member.

List members

GET /workspace/members — active members of the key's workspace with everything linked to them. Use it to build a "CRM manager → workspace member" picker in your settings screen and to see what is already configured.

curl https://app.specala.ai/api/v1/developer/workspace/members \
  -H "Authorization: Bearer sk_live_your_key_here"
{
  "items": [
    {
      "id": "9c2d4e6f-1a2b-4c3d-8e9f-0a1b2c3d4e5f",
      "email": "alex@company.com",
      "name": "Alex Morgan",
      "role": "user",
      "identities": [
        { "provider": "hubspot", "external_id": "12345" },
        { "provider": "aircall", "external_id": "101" }
      ]
    }
  ],
  "total": 1
}
FieldTypeDescription
items[].idUUIDMember id — also valid as X-Author: user:<id> and as {user_id} below.
items[].emailstringThe email they signed up with — also valid as X-Author: email:<address>.
items[].namestring | nullDisplay name.
items[].rolestringowner or user.
items[].identities[]arrayLinked identifiers as { provider, external_id }. Empty if none.

Only active members are returned; pending invitations are not. The list is not paginated (workspaces are small) and is capped at 1000 members.

PUT /workspace/members/{user_id}/identities — link one identifier to a member. Idempotent: linking the same pair again returns 200 instead of 201.

curl -X PUT https://app.specala.ai/api/v1/developer/workspace/members/9c2d4e6f-1a2b-4c3d-8e9f-0a1b2c3d4e5f/identities \
  -H "Authorization: Bearer sk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"provider": "hubspot", "external_id": "12345"}'
import httpx

resp = httpx.put(
    "https://app.specala.ai/api/v1/developer/workspace/members/9c2d4e6f-1a2b-4c3d-8e9f-0a1b2c3d4e5f/identities",
    headers={"Authorization": "Bearer sk_live_your_key_here"},
    json={"provider": "hubspot", "external_id": "12345"},
)
resp.raise_for_status()   # 201 created, 200 already linked
const res = await fetch(
  "https://app.specala.ai/api/v1/developer/workspace/members/9c2d4e6f-1a2b-4c3d-8e9f-0a1b2c3d4e5f/identities",
  {
    method: "PUT",
    headers: {
      Authorization: "Bearer sk_live_your_key_here",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ provider: "hubspot", external_id: "12345" }),
  },
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
FieldRules
providerYour label for the external system: 1–32 characters, a-z, 0-9, _, -. Lowercased on save. There is no fixed list — hubspot, salesforce, pipedrive, aircall, ringcentral are just conventions.
external_idThe person's identifier in that system: 1–128 printable ASCII characters, matched exactly (case-sensitive).

One member can have any number of identifiers — a CRM id and two extensions, say. But one provider + external_id pair points to exactly one member per workspace: linking it to someone else returns 409 identity_conflict until you unlink it first.

Response: 201 (created) or 200 (already linked) with { "provider", "external_id" }.

DELETE /workspace/members/{user_id}/identities/{provider}/{external_id} — 204 on success, 404 if nothing was linked. URL-encode external_id if it contains / or :.

curl -X DELETE https://app.specala.ai/api/v1/developer/workspace/members/9c2d4e6f-1a2b-4c3d-8e9f-0a1b2c3d4e5f/identities/hubspot/12345 \
  -H "Authorization: Bearer sk_live_your_key_here"

Lifecycle

  • When a member is removed from the workspace, their identifiers are deleted with them. Uploads naming them then fail with 422 author_not_member — re-link after they rejoin.
  • Identifiers live inside a workspace: the same hubspot:12345 in another workspace is a different person.

Errors

StatusCodeWhen
403members_scope_requiredKey has no member permission.
403api_key_requiredCalled with an OAuth token instead of an API key.
404member_not_founduser_id is not an active member of the key's workspace.
404identity_not_foundNothing to unlink.
409identity_conflictThe pair is linked to another member.
422invalid_identityprovider or external_id does not match the rules above.

On this page