← Heimdall Docs

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_KEY for admin operations
  • Content-Type: application/json for 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.

POST
/v1/apps

Create a new App

GET
/v1/apps

List all Apps

GET
/v1/apps/:app_name

Get an App by name

PATCH
/v1/apps/:app_name

Update an App

DELETE
/v1/apps/:app_name

Archive 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.

POST
/v1/apps/:app_name/users

Create a user

GET
/v1/apps/:app_name/users

List users in an App

GET
/v1/apps/:app_name/users/:user_id

Get a user by ID

PATCH
/v1/apps/:app_name/users/:user_id

Update a user

DELETE
/v1/apps/:app_name/users/:user_id

Deactivate a user

POST
/v1/apps/:app_name/users/:user_id/roles

Assign a role to a user

DELETE
/v1/apps/:app_name/users/:user_id/roles/:role_name

Remove 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.

POST
/v1/apps/:app_name/roles

Create a role

GET
/v1/apps/:app_name/roles

List roles in an App

GET
/v1/apps/:app_name/roles/:role_name

Get a role by name

PATCH
/v1/apps/:app_name/roles/:role_name

Update a role (including permissions)

DELETE
/v1/apps/:app_name/roles/:role_name

Delete 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.

POST
/v1/apps/:app_name/tokens

Issue an access token

POST
/v1/apps/:app_name/tokens/refresh

Refresh an access token

POST
/v1/apps/:app_name/tokens/revoke

Revoke a refresh token

POST
/v1/authorize

Verify token and check permission

GET
/v1/.well-known/jwks.json

Public 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.

POST
/v1/apps/:app_name/credentials

Create service credentials

GET
/v1/apps/:app_name/credentials

List service credentials

PATCH
/v1/apps/:app_name/credentials/:credential_id

Update credentials (e.g., rotate secret)

DELETE
/v1/apps/:app_name/credentials/:credential_id

Revoke 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.

POST
/v1/apps/:app_name/invites

Create an invite

GET
/v1/apps/:app_name/invites

List pending invites

POST
/v1/invites/:invite_token/accept

Accept an invite

DELETE
/v1/apps/:app_name/invites/:invite_id

Revoke 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.

GET
/v1/apps/:app_name/audit-logs

List audit log entries (paginated, filterable)

GET
/v1/apps/:app_name/audit-logs/:log_id

Get 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_KEY

Response

{
  "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.