API Reference
Every Heimdall endpoint documented with request and response examples. All paths are relative to the base URL: https://api.productcraft.co/heimdall
Common headers
Authorization: Bearer YOUR_ADMIN_KEYfor admin operationsContent-Type: application/jsonfor all request bodies
Error responses
All errors follow a consistent shape:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "email is required",
"details": [
{ "field": "email", "reason": "required" }
]
}
}HTTP status codes follow standard conventions: 400 for validation errors, 401 for missing or invalid credentials, 403 for insufficient permissions, 404 for not found, 409 for conflicts, and 429 for rate limiting.
Apps
Manage tenants. Each App is an isolated namespace containing its own users, roles, and permissions.
/v1/appsCreate a new App
/v1/appsList all Apps
/v1/apps/:app_nameGet an App by name
/v1/apps/:app_nameUpdate an App
/v1/apps/:app_nameArchive an App
Example: Create an App
Request
POST /v1/apps
Content-Type: application/json
Authorization: Bearer YOUR_ADMIN_KEY
{
"name": "acme-corp",
"display_name": "Acme Corporation",
"metadata": {
"plan": "growth",
"region": "us-east-1"
}
}Response
{
"id": "app_01HQ3KXFG6...",
"name": "acme-corp",
"display_name": "Acme Corporation",
"status": "active",
"metadata": {
"plan": "growth",
"region": "us-east-1"
},
"created_at": "2026-02-20T10:00:00Z",
"updated_at": "2026-02-20T10:00:00Z"
}Users
Manage user identities within an App. Users can hold multiple roles and authenticate to receive tokens.
/v1/apps/:app_name/usersCreate a user
/v1/apps/:app_name/usersList users in an App
/v1/apps/:app_name/users/:user_idGet a user by ID
/v1/apps/:app_name/users/:user_idUpdate a user
/v1/apps/:app_name/users/:user_idDeactivate a user
/v1/apps/:app_name/users/:user_id/rolesAssign a role to a user
/v1/apps/:app_name/users/:user_id/roles/:role_nameRemove a role from a user
Example: Create a user
Request
POST /v1/apps/acme-corp/users
Content-Type: application/json
Authorization: Bearer YOUR_ADMIN_KEY
{
"email": "jane@acme.co",
"display_name": "Jane Chen",
"password": "...",
"role": "admin",
"metadata": {
"department": "engineering"
}
}Response
{
"id": "usr_01HQ3KXFG6...",
"app_id": "app_01HQ3KXFG6...",
"email": "jane@acme.co",
"display_name": "Jane Chen",
"roles": ["admin"],
"status": "active",
"metadata": {
"department": "engineering"
},
"created_at": "2026-02-20T10:02:00Z"
}Roles
Define named collections of permissions. Assign roles to users to control what they can do within an App.
/v1/apps/:app_name/rolesCreate a role
/v1/apps/:app_name/rolesList roles in an App
/v1/apps/:app_name/roles/:role_nameGet a role by name
/v1/apps/:app_name/roles/:role_nameUpdate a role (including permissions)
/v1/apps/:app_name/roles/:role_nameDelete a role
Example: Create a role
Request
POST /v1/apps/acme-corp/roles
Content-Type: application/json
Authorization: Bearer YOUR_ADMIN_KEY
{
"name": "editor",
"display_name": "Editor",
"permissions": [
"projects:read",
"projects:write",
"comments:read",
"comments:write"
]
}Response
{
"id": "role_01HQ3KXFG6...",
"app_id": "app_01HQ3KXFG6...",
"name": "editor",
"display_name": "Editor",
"permissions": [
"projects:read",
"projects:write",
"comments:read",
"comments:write"
],
"created_at": "2026-02-20T10:01:00Z"
}Tokens
Authenticate users and services. Returns signed JWTs with App, role, and permission claims.
/v1/apps/:app_name/tokensIssue an access token
/v1/apps/:app_name/tokens/refreshRefresh an access token
/v1/apps/:app_name/tokens/revokeRevoke a refresh token
/v1/authorizeVerify token and check permission
/v1/.well-known/jwks.jsonPublic JWKS endpoint for local verification
Example: Issue a token (user)
Request
POST /v1/apps/acme-corp/tokens
Content-Type: application/json
{
"grant_type": "password",
"email": "jane@acme.co",
"password": "..."
}Response
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rt_01HQ3KXFG6..."
}Service Credentials (M2M)
Create and manage service accounts for machine-to-machine authentication. Each credential set is scoped to specific permissions.
/v1/apps/:app_name/credentialsCreate service credentials
/v1/apps/:app_name/credentialsList service credentials
/v1/apps/:app_name/credentials/:credential_idUpdate credentials (e.g., rotate secret)
/v1/apps/:app_name/credentials/:credential_idRevoke service credentials
Example: Create service credentials
Request
POST /v1/apps/acme-corp/credentials
Content-Type: application/json
Authorization: Bearer YOUR_ADMIN_KEY
{
"name": "billing-service",
"permissions": [
"billing:read",
"billing:write"
]
}Response
{
"id": "cred_01HQ3KXFG6...",
"app_id": "app_01HQ3KXFG6...",
"name": "billing-service",
"client_id": "svc_01HQ3...",
"client_secret": "sk_live_01HQ3...",
"permissions": [
"billing:read",
"billing:write"
],
"created_at": "2026-02-20T10:05:00Z"
}Invites
Generate invite links to onboard new users into an App with a predefined role.
/v1/apps/:app_name/invitesCreate an invite
/v1/apps/:app_name/invitesList pending invites
/v1/invites/:invite_token/acceptAccept an invite
/v1/apps/:app_name/invites/:invite_idRevoke an invite
Example: Create an invite
Request
POST /v1/apps/acme-corp/invites
Content-Type: application/json
Authorization: Bearer YOUR_ADMIN_KEY
{
"email": "bob@contractor.io",
"role": "editor",
"expires_in_hours": 72,
"max_uses": 1
}Response
{
"id": "inv_01HQ3KXFG6...",
"app_id": "app_01HQ3KXFG6...",
"email": "bob@contractor.io",
"role": "editor",
"token": "inv_tok_01HQ3...",
"invite_url": "https://api.productcraft.co/heimdall/v1/invites/inv_tok_01HQ3.../accept",
"expires_at": "2026-02-23T10:00:00Z",
"max_uses": 1,
"uses": 0,
"created_at": "2026-02-20T10:10:00Z"
}Audit Logs
Query the immutable audit trail for any App. Every authentication event and permission change is recorded.
/v1/apps/:app_name/audit-logsList audit log entries (paginated, filterable)
/v1/apps/:app_name/audit-logs/:log_idGet a specific audit log entry
Example: Query audit logs
Request
GET /v1/apps/acme-corp/audit-logs?action=role.assigned&limit=10
Authorization: Bearer YOUR_ADMIN_KEYResponse
{
"data": [
{
"id": "aud_01HQ3KXFG6...",
"app_id": "app_01HQ3KXFG6...",
"actor_id": "usr_01HQ3...",
"action": "role.assigned",
"target_type": "user",
"target_id": "usr_01HQ4...",
"metadata": { "role": "editor" },
"ip_address": "203.0.113.42",
"timestamp": "2026-02-20T10:15:00Z"
}
],
"pagination": {
"total": 47,
"limit": 10,
"offset": 0,
"has_more": true
}
}Rate Limiting
API requests are rate limited per Admin API key. Current limits:
- Admin endpoints: 100 requests per minute
- Token endpoints: 300 requests per minute
- Authorize endpoint: 1000 requests per minute
Rate limit headers are included in every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
Pagination
List endpoints support offset-based pagination with the following query parameters:
limit- Number of items per page (default 20, max 100)offset- Number of items to skip (default 0)
All list responses include a pagination object with total, limit, offset, and has_more.