API Reference

Iluuna provides a REST API at https://app.iluuna.com/api/v1. All responses are JSON.

Base URL: https://app.iluuna.com/api/v1

Authentication

All API requests must include your API key in the Authorization header as a Bearer token. Generate keys in Settings → Integrations → API Keys.

Authorization header
Authorization: Bearer ak_live_your_key_here
Keep your API key secret. Never expose it in client-side code or public repositories. Keys can be revoked instantly from your dashboard.

Rate Limits

The API allows 100 requests per minute per organization. Rate limit information is returned in every response header.

Rate limit headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1749207660

When the limit is exceeded, the API returns 429 Too Many Requests. The X-RateLimit-Reset timestamp indicates when the window resets (Unix epoch seconds).

Estates

An estate represents a family workspace — a secure aftercare hub created for one deceased person. Estates track task progress, document uploads, and collaborator access.

POST/api/v1/estatesCreate Estate

Creates a new family workspace and sends an invitation to the executor. Returns anactivation_url to share with the family.

Request body

FieldTypeRequiredDescription
deceased_namestringYesFull legal name of the deceased
family_contact_emailstringYesEmail address for the executor / family contact
family_contact_namestringNoDisplay name for the executor
date_of_deathstringNoISO 8601 date (YYYY-MM-DD)

Request

curl -X POST https://app.iluuna.com/api/v1/estates \
  -H "Authorization: Bearer ak_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "deceased_name": "James R. Wilson",
    "family_contact_name": "Sarah Wilson",
    "family_contact_email": "sarah@example.com",
    "date_of_death": "2026-06-01"
  }'

Response

// 201 Created
{
  "estate_id": "3c4e9a2b-f18d-4bc7-...",
  "status": "pending_activation",
  "activation_url": "https://app.iluuna.com/invite/tok_..."
}
GET/api/v1/estatesList Estates

Returns all estates for your organization, ordered by most recently created. Includes progress percentage and last activity timestamp.

Request

curl https://app.iluuna.com/api/v1/estates \
  -H "Authorization: Bearer ak_live_..."

Response

// 200 OK
{
  "estates": [
    {
      "estate_id": "3c4e9a2b-...",
      "deceased_name": "James R. Wilson",
      "status": "active",
      "progress": 42,
      "created_at": "2026-06-01T10:00:00Z",
      "last_activity": "2026-06-05T14:32:00Z"
    }
  ]
}

Status values: draft invited active completed

GET/api/v1/estates/{id}Get Estate

Returns detailed status, task progress, and health score for a single estate.

Request

curl https://app.iluuna.com/api/v1/estates/3c4e9a2b-... \
  -H "Authorization: Bearer ak_live_..."

Response

// 200 OK
{
  "estate_id": "3c4e9a2b-...",
  "status": "active",
  "activation_status": "activated",
  "progress": 42,
  "health_score": 85,
  "health": "healthy",
  "tasks_total": 24,
  "tasks_completed": 10,
  "last_activity": "2026-06-05T14:32:00Z"
}

activation_status: not_invited | invitation_sent | activated

health: new | healthy | at_risk | inactive

health_score: 0–100 (85 = healthy, 40 = at risk, 10 = inactive, 60 = new)

Webhook Management

Register, update, and delete webhook endpoints that receive estate lifecycle events. You can also manage webhooks from Settings → Integrations → Webhooks in your dashboard.

GET/api/v1/webhooksList Webhooks

Request

curl https://app.iluuna.com/api/v1/webhooks \
  -H "Authorization: Bearer ak_live_..."

Response

// 200 OK
{
  "webhooks": [
    {
      "webhook_id": "wh_abc123...",
      "url": "https://your-server.com/hooks/iluuna",
      "active": true,
      "event_types": ["estate.created", "estate.activated"],
      "created_at": "2026-06-01T08:00:00Z"
    }
  ]
}
POST/api/v1/webhooksCreate Webhook

Registers a new endpoint. The signing secret is returned once — store it securely.

Request

curl -X POST https://app.iluuna.com/api/v1/webhooks \
  -H "Authorization: Bearer ak_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/hooks/iluuna",
    "event_types": ["estate.created", "estate.activated"]
  }'

Response

// 201 Created
{
  "webhook_id": "wh_abc123...",
  "url": "https://your-server.com/hooks/iluuna",
  "active": true,
  "event_types": ["estate.created", "estate.activated"],
  "secret": "whsec_...",
  "created_at": "2026-06-01T08:00:00Z"
}
PATCH/api/v1/webhooks/{id}Update Webhook

Update the URL, event types, or active status. All fields are optional.

Request

curl -X PATCH https://app.iluuna.com/api/v1/webhooks/wh_abc123 \
  -H "Authorization: Bearer ak_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "active": false,
    "event_types": ["estate.completed"]
  }'

Response

// 200 OK
{
  "webhook_id": "wh_abc123...",
  "url": "https://your-server.com/hooks/iluuna",
  "active": false,
  "event_types": ["estate.completed"],
  "updated_at": "2026-06-05T10:00:00Z"
}
DELETE/api/v1/webhooks/{id}Delete Webhook

Request

curl -X DELETE https://app.iluuna.com/api/v1/webhooks/wh_abc123 \
  -H "Authorization: Bearer ak_live_..."

Response

// 200 OK
{
  "deleted": true
}

Webhook Events

When an event fires, Iluuna sends a POST request to your registered URL with a signed JSON payload. All deliveries include a X-Iluuna-Signature header for verification.

Payload structure
{
  "event": "estate.activated",
  "occurred_at": "2026-06-05T14:32:00Z",
  "data": {
    "estate_id": "3c4e9a2b-f18d-4bc7-8e2a-1a7f6c5d4e3b",
    "deceased_name": "James R. Wilson",
    "status": "active"
  }
}

Signature verification (Node.js)

const crypto = require("crypto");

app.post("/hooks/iluuna", (req, res) => {
  const rawBody = req.body; // raw Buffer — do NOT parse JSON first
  const signature = req.headers["x-iluuna-signature"];

  const expected = "sha256=" + crypto
    .createHmac("sha256", process.env.ILUUNA_WEBHOOK_SECRET)
    .update(rawBody)
    .digest("hex");

  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send("Invalid signature");
  }

  const payload = JSON.parse(rawBody.toString());
  // handle payload.event ...
  res.sendStatus(200);
});
EventDescription
estate.createdA new family workspace was created
estate.activatedThe family executor accepted their invitation
estate.progress_updatedTask completion percentage changed
estate.completedAll required tasks marked complete
family_contact.acceptedA family member accepted their invitation
collaborator.joinedA lawyer, advisor, or accountant joined
document.uploadedA document added to the estate vault
task.completedAn individual task marked complete
webhook.testTest delivery triggered from the dashboard
Retry behaviour: Failed deliveries are retried 3 times with exponential backoff (immediately, 500 ms, 1.5 s). After 3 failures, delivery is queued for a deferred retry at +5 minutes. View delivery logs in Settings → Integrations → Webhooks.

Error Codes

All errors follow a consistent shape: {"error": "ERROR_CODE", "message": "human-readable"}

HTTPError codeMeaning
401UNAUTHORIZEDMissing or invalid API key
402SUBSCRIPTION_REQUIREDYour plan does not allow this operation
403FORBIDDENAPI key does not have permission
404NOT_FOUNDThe requested resource does not exist
422VALIDATION_ERRORRequest body failed validation
429RATE_LIMITED100 requests/min limit exceeded
500INTERNAL_ERRORUnexpected server error

Best Practices

Store the webhook secret immediately

The signing secret is returned once at creation time. Store it in an environment variable. If lost, delete the webhook and create a new one.

Verify every webhook signature

Use crypto.timingSafeEqual to compare signatures. Reject payloads that don't match. Always use the raw request body, not a parsed JSON string.

Respond quickly to webhooks

Return HTTP 200 within 5 seconds. Offload processing to a background queue. Slow responses will be counted as failures and trigger retries.

Handle duplicate events

Webhooks may occasionally deliver the same event more than once. Design your handler to be idempotent — check if you've already processed the estate_id + event combination.

Use one API key per environment

Create separate keys for production and staging. Revoke staging keys before going live. Label keys clearly in Settings → Integrations.

Respect rate limits

Check X-RateLimit-Remaining before batch operations. Implement exponential backoff when you receive a 429 response.

Questions? Contact us or start a free trial to get API access.