API Reference
Iluuna provides a REST API at https://app.iluuna.com/api/v1. All responses are JSON.
https://app.iluuna.com/api/v1Authentication
All API requests must include your API key in the Authorization header as a Bearer token. Generate keys in Settings → Integrations → API Keys.
Authorization: Bearer ak_live_your_key_here
Rate Limits
The API allows 100 requests per minute per organization. Rate limit information is returned in every response header.
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.
/api/v1/estates— Create EstateCreates a new family workspace and sends an invitation to the executor. Returns anactivation_url to share with the family.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
| deceased_name | string | Yes | Full legal name of the deceased |
| family_contact_email | string | Yes | Email address for the executor / family contact |
| family_contact_name | string | No | Display name for the executor |
| date_of_death | string | No | ISO 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_..."
}/api/v1/estates— List EstatesReturns 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
/api/v1/estates/{id}— Get EstateReturns 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.
/api/v1/webhooks— List WebhooksRequest
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"
}
]
}/api/v1/webhooks— Create WebhookRegisters 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"
}/api/v1/webhooks/{id}— Update WebhookUpdate 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"
}/api/v1/webhooks/{id}— Delete WebhookRequest
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.
{
"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);
});| Event | Description |
|---|---|
estate.created | A new family workspace was created |
estate.activated | The family executor accepted their invitation |
estate.progress_updated | Task completion percentage changed |
estate.completed | All required tasks marked complete |
family_contact.accepted | A family member accepted their invitation |
collaborator.joined | A lawyer, advisor, or accountant joined |
document.uploaded | A document added to the estate vault |
task.completed | An individual task marked complete |
webhook.test | Test delivery triggered from the dashboard |
Error Codes
All errors follow a consistent shape: {"error": "ERROR_CODE", "message": "human-readable"}
| HTTP | Error code | Meaning |
|---|---|---|
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 402 | SUBSCRIPTION_REQUIRED | Your plan does not allow this operation |
| 403 | FORBIDDEN | API key does not have permission |
| 404 | NOT_FOUND | The requested resource does not exist |
| 422 | VALIDATION_ERROR | Request body failed validation |
| 429 | RATE_LIMITED | 100 requests/min limit exceeded |
| 500 | INTERNAL_ERROR | Unexpected 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.