API Keys API
REST endpoints for api keys — request and response reference with examples.
Create and revoke API keys programmatically, or self-serve in the app: Settings → API Keys → Create API Key.
Base URL: https://api.actuallycare.com/v1 · Errors use the standard envelope — see Errors.
List API keys#
Returns list of API keys for authenticated user (keys are masked)
Responses#
| Status | Meaning |
|---|---|
200 | API keys retrieved successfully |
401 | Unauthorized |
429 | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
500 | Internal server error |
Example request#
curl "https://api.actuallycare.com/v1/api-keys" \
-H "Authorization: Bearer YOUR_JWT"const res = await fetch("https://api.actuallycare.com/v1/api-keys", {
headers: {
"Authorization": "Bearer YOUR_JWT",
},
});
const data = await res.json();import requests
resp = requests.get(
"https://api.actuallycare.com/v1/api-keys",
headers={"Authorization": "Bearer YOUR_JWT"},
)
data = resp.json()Example response (200)#
{
"success": true,
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Jordan Lee",
"key_preview": "example key preview",
"is_active": true,
"created_at": "2026-07-15T14:32:10.000Z",
"last_used_at": "2026-07-15T14:32:10.000Z",
"expires_at": "2026-07-15T14:32:10.000Z"
}
]
}Create new API key#
Generates a new API key for authenticated user. Key is only shown once.
⚠️ CONSEQUENTIAL ACTION: Creates new authentication credentials. Store the key securely - it cannot be retrieved again.
Request body#
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Descriptive name for the API key |
expiresInDays | integer | No | Number of days until expiration (1-365). If omitted, the key does not expire. |
scopes | object | No | Map of resource → allowed actions (an OBJECT, not a string array), e.g. {"escrows": ["read", "write"], "clients": ["read"]}. Use resource "all" as a wildcard (e.g. {"all": ["read"]}). Valid resources: all, escrows, clients, contacts, leads, appointments, listings, documents, open-houses, showings, details, tasks, notes, communications, emails, integrations, settings, analytics, activity, notifications, users, search, teams, vendor-applications. If omitted, the key is created with {} (no scopes) and is DENIED (403) on every scoped resource — pass scopes here or grant them later via PATCH /api-keys/{id}/scopes. |
Responses#
| Status | Meaning |
|---|---|
201 | API key created successfully |
400 | Validation error |
401 | Unauthorized |
429 | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
500 | Internal server error |
Example request#
curl -X POST "https://api.actuallycare.com/v1/api-keys" \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{
"name": "Jordan Lee",
"scopes": {
"all": [
"read"
],
"escrows": [
"read",
"write"
]
}
}'const res = await fetch("https://api.actuallycare.com/v1/api-keys", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_JWT",
"Content-Type": "application/json",
},
body: JSON.stringify({
"name": "Jordan Lee",
"scopes": {
"all": [
"read"
],
"escrows": [
"read",
"write"
]
}
}),
});
const data = await res.json();import requests
resp = requests.post(
"https://api.actuallycare.com/v1/api-keys",
headers={"Authorization": "Bearer YOUR_JWT"},
json={
"name": "Jordan Lee",
"scopes": {
"all": [
"read"
],
"escrows": [
"read",
"write"
]
}
},
)
data = resp.json()Example response (201)#
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"key": "example key",
"name": "Jordan Lee",
"key_prefix": "example key prefix",
"scopes": {},
"expires_at": "2026-07-15T14:32:10.000Z",
"created_at": "2026-07-15T14:32:10.000Z"
},
"message": "example message",
"timestamp": "2026-07-15T14:32:10.000Z"
}Update API key scopes#
Replaces the scopes object on an existing API key. Requires JWT authentication (API keys cannot manage API keys). Scopes are a map of resource → allowed actions; see POST /api-keys for the valid resource list.
Parameters#
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Format: uuid |
Request body#
| Field | Type | Required | Description |
|---|---|---|---|
scopes | object | Yes | Full replacement scopes map (resource → actions) |
Responses#
| Status | Meaning |
|---|---|
200 | Scopes updated |
400 | Validation error (scopes must be an object) |
401 | Unauthorized |
404 | API key not found |
429 | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
500 | Internal server error |
Example request#
curl -X PATCH "https://api.actuallycare.com/v1/api-keys/:id/scopes" \
-H "Authorization: Bearer YOUR_JWT" \
-H "Content-Type: application/json" \
-d '{
"scopes": {
"escrows": [
"read",
"write"
],
"all": [
"read"
]
}
}'const res = await fetch("https://api.actuallycare.com/v1/api-keys/:id/scopes", {
method: "PATCH",
headers: {
"Authorization": "Bearer YOUR_JWT",
"Content-Type": "application/json",
},
body: JSON.stringify({
"scopes": {
"escrows": [
"read",
"write"
],
"all": [
"read"
]
}
}),
});
const data = await res.json();import requests
resp = requests.patch(
"https://api.actuallycare.com/v1/api-keys/:id/scopes",
headers={"Authorization": "Bearer YOUR_JWT"},
json={
"scopes": {
"escrows": [
"read",
"write"
],
"all": [
"read"
]
}
},
)
data = resp.json()Example response (200)#
{
"success": true,
"data": {
"id": "7d3f9b2e-5a8c-4e1d-b6f0-9c2a4e8d1b57",
"scopes": {
"escrows": [
"read",
"write"
],
"all": [
"read"
]
}
},
"timestamp": "2026-07-01T22:48:31.554Z"
}Revoke API key#
Deactivates an API key without deleting it
Parameters#
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Format: uuid |
Responses#
| Status | Meaning |
|---|---|
200 | API key revoked successfully |
401 | Unauthorized |
404 | API key not found |
429 | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
500 | Internal server error |
Example request#
curl -X PUT "https://api.actuallycare.com/v1/api-keys/:id/revoke" \
-H "Authorization: Bearer YOUR_JWT"const res = await fetch("https://api.actuallycare.com/v1/api-keys/:id/revoke", {
method: "PUT",
headers: {
"Authorization": "Bearer YOUR_JWT",
},
});
const data = await res.json();import requests
resp = requests.put(
"https://api.actuallycare.com/v1/api-keys/:id/revoke",
headers={"Authorization": "Bearer YOUR_JWT"},
)
data = resp.json()Example response (200)#
{
"success": true,
"data": {
"id": "7d3f9b2e-5a8c-4e1d-b6f0-9c2a4e8d1b57"
},
"timestamp": "2026-07-01T22:53:07.114Z"
}Delete API key#
Permanently deletes an API key
Parameters#
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | Yes | Format: uuid |
Responses#
| Status | Meaning |
|---|---|
200 | API key deleted successfully |
401 | Unauthorized |
404 | API key not found |
429 | Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying. |
500 | Internal server error |
Example request#
curl -X DELETE "https://api.actuallycare.com/v1/api-keys/:id" \
-H "Authorization: Bearer YOUR_JWT"const res = await fetch("https://api.actuallycare.com/v1/api-keys/:id", {
method: "DELETE",
headers: {
"Authorization": "Bearer YOUR_JWT",
},
});
const data = await res.json();import requests
resp = requests.delete(
"https://api.actuallycare.com/v1/api-keys/:id",
headers={"Authorization": "Bearer YOUR_JWT"},
)
data = resp.json()Example response (200)#
{
"success": true,
"data": {},
"timestamp": "2026-07-15T14:32:10.000Z"
}