Account API
Self-serve control surface. Dashboard/admin credential — never ship it in a product build.
Credential: as_ account session · scheme as_ account session
11 operations · 11 captured against the live API.
Every example below is a real exchange recorded against a throwaway tenant, then redacted — not a
shape transcribed from a schema. Ids and timestamps are stable fixtures so the same request always
reads the same way. Back to the full index →
Account #
Create an account and its tenant
Request
curl -X POST https://api.ollacore.com/v1/account/signup \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"<redacted>"}' {
"email": "[email protected]",
"password": "<redacted>"
} | Parameter | Type | Description |
|---|---|---|
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
|---|---|---|
email required | string (email) | Your email address; it becomes the login. Stored lowercased. Not verified: there is no email step. |
password required | string min length 12 · max length 256 | 12–256 characters. Stored only as an argon2 hash. |
Response · 200
{
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"session_token": "as_EXAMPLE_SESSION",
"expires_at": "2026-02-14T09:30:00Z"
} Response fields (3)
| Field | Type | Description |
|---|---|---|
tenant_id required | string | The account's auto-provisioned tenant. |
session_token required | string | Opaque bearer (as_...), shown once. |
expires_at required | string (date-time) | When this session stops working: 30 days after it was issued. Log in again for a new one. |
Errors · 409
| Status | When |
|---|---|
409 | email already registered |
Log in
Request
curl -X POST https://api.ollacore.com/v1/account/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"<redacted>"}' {
"email": "[email protected]",
"password": "<redacted>"
} | Parameter | Type | Description |
|---|---|---|
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
|---|---|---|
email required | string (email) | The email you signed up with. |
password required | string | Your password. |
Response · 200
{
"tenant_id": "acct_fac91b282191cc02dd29912c8db43f1c",
"session_token": "as_EXAMPLE_SESSION",
"expires_at": "2026-02-14T09:30:01Z"
} Response fields (3)
| Field | Type | Description |
|---|---|---|
tenant_id required | string | The account's auto-provisioned tenant. |
session_token required | string | Opaque bearer (as_...), shown once. |
expires_at required | string (date-time) | When this session stops working: 30 days after it was issued. Log in again for a new one. |
Errors · 401
| Status | When |
|---|---|
401 | Missing, expired or invalid credentials |
Invalidate the session
Request
curl -X POST https://api.ollacore.com/v1/account/logout \
-H "Authorization: Bearer as_…" \
-H "Content-Type: application/json" \
-d '{}' {} | Parameter | Type | Description |
|---|---|---|
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"logged_out": true
} Response fields (1)
| Field | Type | Description |
|---|---|---|
logged_out | boolean | True when this call removed the session. False only if a concurrent logout removed it first; either way the session no longer works. |
Errors · 401
| Status | When |
|---|---|
401 | Missing, expired or invalid credentials |
API keys #
List keys
Request
curl -X GET https://api.ollacore.com/v1/account/api-keys \
-H "Authorization: Bearer as_…" | Parameter | Type | Description |
|---|---|---|
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"api_keys": [
{
"created_at": "2026-01-15T09:30:01Z",
"environment": "live",
"expires_at": null,
"id": "key-id-main",
"last_used_at": null,
"name": "docs-example-key",
"plan": "default",
"revoked_at": null,
"scopes": [
"rooms:read",
"rooms:write",
"members:write",
"tokens:mint",
"messages:write",
"webhooks:manage",
"usage:read",
"rooms:delete",
"data:erase"
]
}
]
} Response fields (1)
| Field | Type | Description |
|---|---|---|
api_keys | array of object | The account's keys, without secrets. |
Errors · 401
| Status | When |
|---|---|
401 | Missing, expired or invalid credentials |
Create a key (secret shown once)
Request
curl -X POST https://api.ollacore.com/v1/account/api-keys \
-H "Authorization: Bearer as_…" \
-H "Content-Type: application/json" \
-d '{"name":"docs-example-key","environment":"live","scopes":["rooms:read","rooms:write","members:write","tokens:mint","messages:write","webhooks:manage","usage:read","rooms:delete","data:erase"]}' {
"name": "docs-example-key",
"environment": "live",
"scopes": [
"rooms:read",
"rooms:write",
"members:write",
"tokens:mint",
"messages:write",
"webhooks:manage",
"usage:read",
"rooms:delete",
"data:erase"
]
} | Parameter | Type | Description |
|---|---|---|
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
|---|---|---|
name | string | Optional label for the key, for your own records. |
environment required | one of: live, test | live or test. A test key works in its own data namespace and never sees live data. |
scopes | array of one of: rooms:read, rooms:write, members:write, tokens:mint, messages:write, webhooks:manage, usage:read, rooms:delete, data:erase | Scopes to grant. Omit for the default set: rooms:read, rooms:write, members:write, tokens:mint, messages:write. usage:read, webhooks:manage, rooms:delete and data:erase must be asked for. |
Response · 200
{
"key_id": "key-id-main",
"api_key": "ak_live_EXAMPLE.NOT_A_REAL_KEY",
"environment": "live",
"scopes": [
"rooms:read",
"rooms:write",
"members:write",
"tokens:mint",
"messages:write",
"webhooks:manage",
"usage:read",
"rooms:delete",
"data:erase"
]
} Response fields (4)
| Field | Type | Description |
|---|---|---|
key_id required | string | The key's public id (ak_live_… or ak_test_…). Use it to rotate or revoke the key; it is not a credential. |
api_key required | string | Full ak_<env>_<id>.<secret>, shown once. |
environment required | one of: live, test | live or test. A test key sees only test data. |
scopes required | array of one of: rooms:read, rooms:write, members:write, tokens:mint, messages:write, webhooks:manage, usage:read, rooms:delete, data:erase | What the key may do. A call outside these scopes is refused with 403 when it is made. |
Errors · 401
| Status | When |
|---|---|
401 | Missing, expired or invalid credentials |
Rotate atomically
Request
curl -X POST https://api.ollacore.com/v1/account/api-keys/key-id-main/rotate \
-H "Authorization: Bearer as_…" \
-H "Content-Type: application/json" \
-d '{}' {} | Parameter | Type | Description |
|---|---|---|
key_id path required | string | The key's public id (ak_live_… or ak_test_…), as returned when it was created or listed. |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"api_key": "ak_live_EXAMPLE.NOT_A_REAL_KEY",
"key_id": "ak_live_616b8de93a24dfbf2c5839186fd5b29a"
} Response fields (2)
| Field | Type | Description |
|---|---|---|
key_id | string | The replacement key's id. The old key is revoked in the same step. |
api_key | string | The replacement key, ak_<env>_<id>.<secret>. Shown once; store it now. |
Errors · 401 · 404
| Status | When |
|---|---|
401 | Missing, expired or invalid credentials |
404 | not an owned, live key |
Revoke
Request
curl -X DELETE https://api.ollacore.com/v1/account/api-keys/ak_live_e8177c7859fe3139043b58fff01924bd \
-H "Authorization: Bearer as_…" | Parameter | Type | Description |
|---|---|---|
key_id path required | string | The key's public id (ak_live_… or ak_test_…). |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"revoked": true
} Response fields (1)
| Field | Type | Description |
|---|---|---|
revoked | boolean | True once the key no longer works. |
Errors · 401 · 404
| Status | When |
|---|---|
401 | Missing, expired or invalid credentials |
404 | not an owned, live key |
Directory apps #
Provision an app (webhook or SMS provider)
Request
curl -X POST https://api.ollacore.com/v1/account/directory-apps \
-H "Authorization: Bearer as_…" \
-H "Content-Type: application/json" \
-d '{"delivery_webhook_url":"https://hooks.example.com/hook"}' {
"delivery_webhook_url": "https://hooks.example.com/hook"
} | Parameter | Type | Description |
|---|---|---|
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
|---|---|---|
delivery_webhook_url | string (uri) | Webhook mode: where we POST each OTP, signed, for you to deliver. Must be a public https:// URL: one whose address is private, loopback or link-local is refused with 400 here, and every delivery checks again. A name that doesn't resolve yet is accepted now and refused at delivery if it still doesn't. Set this or provider, not both. |
provider | object | Provider mode: your own SMS vendor account, which we call to send the OTP. Set this or delivery_webhook_url, not both. Credentials cannot be updated later; rotate by creating a new app. |
provider. required if its parent is sent | one of: twilio, plivo, msg91 | Which SMS vendor. config holds that vendor's credentials and is validated for it now. |
provider. required if its parent is sent | object | Vendor-specific credentials; validated for kind at creation. |
Response · 200
{
"app_id": "da_03270a6c821fcca6c63a2049d93b62fe",
"delivery_mode": "webhook",
"delivery_secret": "dsec_EXAMPLE_NOT_A_REAL_SECRET",
"delivery_webhook_url": "https://hooks.example.com/hook"
} Response fields (4)
| Field | Type | Description |
|---|---|---|
app_id | string | The app's public id. Safe to ship in your mobile build; the directory endpoints take it to find your tenant. |
delivery_mode | one of: webhook, provider | How OTPs reach users: webhook or provider. |
delivery_secret | string, nullable | HMAC secret, shown once (webhook mode only) |
delivery_webhook_url | string, nullable | The delivery webhook, in webhook mode; null in provider mode. |
Errors · 400 · 401
| Status | When |
|---|---|
400 | Invalid request: both or neither of delivery_webhook_url and provider; a provider configuration of the wrong shape; or a delivery_webhook_url that is not https:// or whose address is not public (private, loopback, link-local or otherwise reserved). A name that does not resolve yet is accepted. |
401 | Missing, expired or invalid credentials |
List apps and which push transports are configured
Request
curl -X GET https://api.ollacore.com/v1/account/directory-apps \
-H "Authorization: Bearer as_…" | Parameter | Type | Description |
|---|---|---|
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"directory_apps": [
{
"app_id": "da_03270a6c821fcca6c63a2049d93b62fe",
"created_at": "2026-01-15T09:30:01Z",
"delivery_mode": "webhook",
"delivery_webhook_url": "https://hooks.example.com/hook",
"push_apns": false,
"push_fcm": false
}
]
} Response fields (1)
| Field | Type | Description |
|---|---|---|
directory_apps | array of object | The account's directory apps. Secrets are never returned. |
Errors · 401
| Status | When |
|---|---|
401 | Missing, expired or invalid credentials |
Delete an app
Request
curl -X DELETE https://api.ollacore.com/v1/account/directory-apps/da_03270a6c821fcca6c63a2049d93b62fe \
-H "Authorization: Bearer as_…" | Parameter | Type | Description |
|---|---|---|
app_id path required | string | The directory app's public id. |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Response · 200
{
"deleted": true
} Response fields (1)
| Field | Type | Description |
|---|---|---|
deleted | boolean | True once the app is gone. Its users and data stay in the tenant. |
Errors · 401 · 404
| Status | When |
|---|---|
401 | Missing, expired or invalid credentials |
404 | not an owned app |
Set FCM/APNs credentials (write-only)
Request
curl -X PUT https://api.ollacore.com/v1/account/directory-apps/da_03270a6c821fcca6c63a2049d93b62fe/push \
-H "Authorization: Bearer as_…" \
-H "Content-Type: application/json" \
-d '{"fcm":{"service_account":{"project_id":"my-firebase-project","client_email":"[email protected]","private_key":"-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----"}},"apns":{"p8":"-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----","key_id":"ABC123DEFG","team_id":"TEAM123456","topic":"com.example.chat","env":"production"}}' {
"fcm": {
"service_account": {
"project_id": "my-firebase-project",
"client_email": "[email protected]",
"private_key": "-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----"
}
},
"apns": {
"p8": "-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----",
"key_id": "ABC123DEFG",
"team_id": "TEAM123456",
"topic": "com.example.chat",
"env": "production"
}
} | Parameter | Type | Description |
|---|---|---|
app_id path required | string | The directory app's public id. |
X-Request-Id header | string | Your own id for this request. It is returned in the response's X-Request-Id header and attached to every log line kept for the request, so quote it when you contact support. Use printable ASCII. Without it, the server assigns a UUID. |
Request fields
| Field | Type | Description |
|---|---|---|
fcm | object, nullable | FCM credentials: service_account is the Google service-account JSON. Omit or null to clear FCM, because this call replaces both sides. |
fcm. required if its parent is sent | object | Google service-account JSON (project_id, client_email, private_key, ...) |
apns | object, nullable | APNs credentials. Omit or null to clear APNs, because this call replaces both sides. |
apns. required if its parent is sent | string | The contents of the APNs .p8 key file (PEM). |
apns. required if its parent is sent | string | The APNs key's 10-character id. |
apns. required if its parent is sent | string | Your Apple developer team id. |
apns. required if its parent is sent | string | The app's bundle id. |
apns. | one of: sandbox, production default "production" | production (TestFlight and App Store) or sandbox (debug builds). Defaults to production. The wrong one fails silently. |
Response · 200
{
"push_apns": true,
"push_fcm": true
} Response fields (2)
| Field | Type | Description |
|---|---|---|
push_fcm | boolean | Whether FCM credentials are now stored. |
push_apns | boolean | Whether APNs credentials are now stored. |
Errors · 400 · 401 · 404
| Status | When |
|---|---|
400 | Invalid push config |
401 | Missing, expired or invalid credentials |
404 | No such room, message, member or attachment |
Errors on this plane #
Every failure uses the same body — code and message. These were
triggered deliberately against the live API.
401 · no Authorization header
{
"code": "unauthorized",
"message": "unauthorized: missing Authorization header"
} 401 · an as_ account session on the server plane
{
"code": "unauthorized",
"message": "unauthorized: malformed API key"
} The full code list and retry guidance is on Errors & rate limits.