Admin API
Organizations (admin)
Provision a tenant. Requires an admin credential
For concepts and a walkthrough, read Operators.
List organizations
/admin/organizationsMetadata only. No endpoint returns credential material — see the note below.
Query parameters
cursorstringlimitintegerMax 100
Response fields 200
itemsOrganizationSummary[]requirednextCursorstring | nullrequiredOpaque. Pass back verbatim as
cursor. Null means the end.hasMorebooleanrequired
OrganizationSummary
idstring (uuid)requiredslugstringrequirednamestringrequiredplanstringrequiredstatusstringrequireddefaultLocalestringrequireddefaultTimezonestringrequired
Responses
- 200A page of organizations, newest first.
- 401Missing or invalid admin credential.
curl "https://api.getengageai.app/admin/organizations" \
-H "Authorization: Bearer $ADMIN_TOKEN"{
"items": [
{
"id": "3f6c2a1e-8b4d-4e7a-9c15-2d0b7e6f4a91",
"slug": "copper-kettle-cafe",
"name": "Copper Kettle Cafe",
"plan": "string",
"status": "string",
"defaultLocale": "en-GB",
"defaultTimezone": "Europe/London"
}
],
"nextCursor": null,
"hasMore": false
}Provision an organization
/admin/organizationsCreates the organization, a default agent profile and a first API key in one transaction. All three or none: an organization without a profile receives messages it can never answer, and one without a key cannot be configured by any endpoint.
The returned key is shown once. Only a peppered hash is stored, so it cannot be recovered — issue a new one instead.
Requires the ADMIN_API_KEY credential, which is separate from tenant keys.
- Body
- application/json
Request body
namestringrequiredDisplay name, e.g. "Acme Outdoors".
Max 255 characters
slugstringURL-safe identifier. Derived from the name when omitted. Immutable once set.
Min 3 characters · Max 63 characters
planenumOne of
FREE,STARTER,GROWTH,ENTERPRISEdefaultLocalestringMax 16 characters
defaultTimezonestringIANA name, e.g. Europe/London.
Max 64 characters
settingsobjectBusiness hours, escalation contacts, branding.
personastringSeeds the default agent profile's persona. Editable afterwards.
Max 4000 characters
environmentenumPrefixes the issued key. Cosmetic; both are equally real.
One of
live,testownerobjectrequiredThe person who will administer this organization. A password is generated for them and returned once, under
login.owner.emailstring (email)requiredThey sign in with this.
Max 320 characters
owner.namestringMax 255 characters
Response fields 201
organizationobjectrequiredorganization.idstring (uuid)requiredorganization.slugstringrequiredorganization.namestringrequiredorganization.planstringrequiredagentProfileIdstring (uuid)requiredThe default profile, created with conservative guardrails.
loginobjectrequiredHand this to the organization.
login.urlstringrequiredWhere to POST them.
login.emailstring (email)requiredlogin.passwordstringrequiredShown once. It appears here and nowhere else — not in the audit log, not in any log line — and only a scrypt hash is stored. Lost means reissue, never retrieve.
login.mustChangePasswordtruerequiredThey are expected to replace it via POST /auth/password.
login.userIdstring (uuid)requiredapiKeyobjectrequiredapiKey.idstring (uuid)requiredapiKey.prefixstringrequiredNon-secret. Safe to store and to quote in support.
apiKey.plaintextstringrequiredShown exactly once. Only a peppered hash is stored, so this cannot be recovered — issue a new key instead.
OrganizationProvisioned
organizationobjectrequiredorganization.idstring (uuid)requiredorganization.slugstringrequiredorganization.namestringrequiredorganization.planstringrequiredagentProfileIdstring (uuid)requiredThe default profile, created with conservative guardrails.
loginobjectrequiredHand this to the organization.
login.urlstringrequiredWhere to POST them.
login.emailstring (email)requiredlogin.passwordstringrequiredShown once. It appears here and nowhere else — not in the audit log, not in any log line — and only a scrypt hash is stored. Lost means reissue, never retrieve.
login.mustChangePasswordtruerequiredThey are expected to replace it via POST /auth/password.
login.userIdstring (uuid)requiredapiKeyobjectrequiredapiKey.idstring (uuid)requiredapiKey.prefixstringrequiredNon-secret. Safe to store and to quote in support.
apiKey.plaintextstringrequiredShown exactly once. Only a peppered hash is stored, so this cannot be recovered — issue a new key instead.
Responses
- 201Provisioned. Store the key now.
- 401Missing or invalid admin credential.
- 409The slug is already taken.
- 422Invalid name, or no slug could be derived from it.
curl -X POST "https://api.getengageai.app/admin/organizations" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Copper Kettle Cafe",
"owner": {
"email": "manager@copperkettle.example",
"name": "Sam Patel"
}
}'{
"organization": {
"id": "3f6c2a1e-8b4d-4e7a-9c15-2d0b7e6f4a91",
"slug": "copper-kettle-cafe",
"name": "Trailhead Mid GTX Boot",
"plan": "string"
},
"agentProfileId": "3f6c2a1e-8b4d-4e7a-9c15-2d0b7e6f4a91",
"login": {
"url": "https://acme.example/products/trailhead-mid",
"email": "owner@acme.example",
"password": "mFGVaAer-jKcyPp34-qxmLNojm",
"mustChangePassword": true,
"userId": "3f6c2a1e-8b4d-4e7a-9c15-2d0b7e6f4a91"
},
"apiKey": {
"id": "3f6c2a1e-8b4d-4e7a-9c15-2d0b7e6f4a91",
"prefix": "eng_live_312cf6e6",
"plaintext": "eng_live_312cf6e6.fPCz8Qk…"
}
}Describe an organization
/admin/organizations/{id}Who can sign in, which API keys exist, and when each was last used — enough to answer a support question.
Credentials are not retrievable. Passwords are stored as scrypt hashes and keys as peppered HMACs; no code path reverses either, deliberately. What you get here are identifiers — emails and key prefixes — never anything usable. When a customer has lost a credential, reissue it below.
Path parameters
idstring (uuid)required
Response fields 200
idstring (uuid)requiredslugstringrequirednamestringrequiredplanstringrequiredstatusstringrequiredmembersobject[]requiredmembers[].userIdstring (uuid)requiredmembers[].emailstring (email)requiredmembers[].namestring | nullrequiredmembers[].rolestringrequiredmembers[].mustChangePasswordbooleanrequiredTrue while the password is one an administrator issued.
members[].lastLoginAtstring (date-time) | nullrequiredNull means they have never signed in.
apiKeysobject[]requiredapiKeys[].idstring (uuid)requiredapiKeys[].namestringrequiredapiKeys[].prefixstringrequiredNon-secret. Identifies a key without being one.
apiKeys[].lastUsedAtstring (date-time) | nullrequiredapiKeys[].revokedAtstring (date-time) | nullrequired
OrganizationDetail
idstring (uuid)requiredslugstringrequirednamestringrequiredplanstringrequiredstatusstringrequiredmembersobject[]requiredmembers[].userIdstring (uuid)requiredmembers[].emailstring (email)requiredmembers[].namestring | nullrequiredmembers[].rolestringrequiredmembers[].mustChangePasswordbooleanrequiredTrue while the password is one an administrator issued.
members[].lastLoginAtstring (date-time) | nullrequiredNull means they have never signed in.
apiKeysobject[]requiredapiKeys[].idstring (uuid)requiredapiKeys[].namestringrequiredapiKeys[].prefixstringrequiredNon-secret. Identifies a key without being one.
apiKeys[].lastUsedAtstring (date-time) | nullrequiredapiKeys[].revokedAtstring (date-time) | nullrequired
Responses
- 200The organization and its credential inventory.
- 404No such organization.
curl "https://api.getengageai.app/admin/organizations/$ID" \
-H "Authorization: Bearer $ADMIN_TOKEN"{
"id": "3f6c2a1e-8b4d-4e7a-9c15-2d0b7e6f4a91",
"slug": "copper-kettle-cafe",
"name": "Copper Kettle Cafe",
"plan": "string",
"status": "string",
"members": [
{
"userId": "3f6c2a1e-8b4d-4e7a-9c15-2d0b7e6f4a91",
"email": "owner@acme.example",
"name": "Copper Kettle Cafe",
"role": "string",
"mustChangePassword": true,
"lastLoginAt": "2026-10-16T09:30:00.000Z"
}
],
"apiKeys": [
{
"id": "3f6c2a1e-8b4d-4e7a-9c15-2d0b7e6f4a91",
"name": "Copper Kettle Cafe",
"prefix": "eng_live_312cf6e6",
"lastUsedAt": "2026-10-16T09:30:00.000Z",
"revokedAt": "2026-10-16T09:30:00.000Z"
}
]
}Issue a new password for a member
/admin/organizations/{id}/password-resetThe recovery path when a customer cannot sign in. Returns a new temporary password, flagged for replacement, and revokes every session that member held — a reset that left live tokens valid would change nothing for whoever already had one.
Defaults to the OWNER; name another member with email.
- Body
- application/json
Path parameters
idstring (uuid)required
Request body
emailstring (email)Which member to reset. Defaults to the OWNER when there is exactly one.
Response fields 201
userIdstring (uuid)requiredemailstring (email)requiredtemporaryPasswordstringrequiredShown once. Every session that member held has been revoked.
mustChangePasswordtruerequired
PasswordReset
userIdstring (uuid)requiredemailstring (email)requiredtemporaryPasswordstringrequiredShown once. Every session that member held has been revoked.
mustChangePasswordtruerequired
Responses
- 201Reset. Hand the password over once.
- 404No such organization, or no such member.
- 422Several members and no OWNER; name one with `email`.
curl -X POST "https://api.getengageai.app/admin/organizations/$ID/password-reset" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'{
"userId": "3f6c2a1e-8b4d-4e7a-9c15-2d0b7e6f4a91",
"email": "owner@acme.example",
"temporaryPassword": "h7TN5737-LD9FH2hW-mJ9uu6oj",
"mustChangePassword": true
}Issue an API key for an organization
/admin/organizations/{id}/api-keysA tenant issues its own keys through POST /api-keys, but only while holding a working credential. This is the way back when every one of them has been lost.
- Body
- application/json
Path parameters
idstring (uuid)required
Request body
namestringDefault
"Replacement key"· Max 128 charactersenvironmentenumOne of
live,test
Response fields 201
idstring (uuid)namestringprefixstringscopesstring[]lastUsedAtstring (date-time) | nullexpiresAtstring (date-time) | nullrevokedAtstring (date-time) | nullcreatedAtstring (date-time)plaintextstringShown exactly once.
Responses
- 201Issued. The plaintext is shown once.
- 404No such organization.
curl -X POST "https://api.getengageai.app/admin/organizations/$ID/api-keys" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Replacement key"
}'{
"id": "3f6c2a1e-8b4d-4e7a-9c15-2d0b7e6f4a91",
"name": "Trailhead Mid GTX Boot",
"prefix": "eng_live_312cf6e6",
"scopes": [
"string"
],
"lastUsedAt": "2026-10-16T09:30:00.000Z",
"expiresAt": "2026-10-16T09:30:00.000Z",
"revokedAt": "2026-10-16T09:30:00.000Z",
"createdAt": "2026-10-16T09:30:00.000Z",
"plaintext": "eng_live_312cf6e6.fPCz8Qk…"
}