Reference

Build on the Lucra API.

Drag a sticker to move it, or use the arrow keys while focused.

Introduction

Your first request, IDs, lists, errors and retries.

One REST API runs everything in Lucra, and the Lucra app is built on it. Call it from your server with the SDK or plain HTTP, or connect an AI assistant over MCP.

Your first request

Create a key in Settings → Developers → API, then call GET /v1/account to see the account it belongs to:

Terminal
curl https://api.onlucra.com/v1/account \
  -H "Authorization: Bearer $LUCRA_API_KEY" \
  -H "Lucra-Version: 2026-10-01"

Every request sends two headers:

  • Authorization: Bearer … with an API key or an OAuth access token. See Authentication.
  • Lucra-Version, so your integration keeps working as the API changes. The SDK sends it for you.

The same call with the SDK:

TypeScript
import { Lucra } from "@lucra/sdk"

const lucra = new Lucra(process.env.LUCRA_API_KEY!)
const { data: account } = await lucra.account.retrieve()

IDs

Every ID starts with a prefix naming its resource, like prog_00lhuAJjQgdtNt5WnqTBc95 for a program. Treat the rest as opaque.

PrefixResource
acct_account
ad_ad
adauth_ad authorization
adset_ad set
agac_agreement acceptance
agr_agreement
appl_application
camp_campaign
conn_connection
conv_conversion
crtr_creator
emb_embed
ern_earning
evt_webhook event
file_file
key_key
msg_message
pay_payment
post_post
pout_payout
prod_product
prog_program
pxev_pixel event
pxl_pixel
ret_retainer
smpl_sample
sub_submission
thr_thread
txn_transaction
wdr_withdrawal

Objects

JSON
{
  "id": "prog_00lhuAJjQgdtNt5WnqTBc95",
  "name": "Spring launch",
  "status": "open",
  "version": 3,
  "createdAt": "2026-10-01T15:04:05.000Z"
}
  • A reference to another object is its bare ID, in a field named for it: program, creator, account.
  • Money is an integer number of cents, next to a currency. Rates are percents.
  • Times are UTC ISO 8601, in fields ending in At.
  • Enums can gain values, so handle ones you don't recognize.

Lists

A list returns data and a nextCursor. Pass that cursor back as cursor to get the next page; it's null on the last one. limit sets the page size (default 25, up to 100).

JSON
{ "data": [{ "id": "prog_00lhuAJjQgdtNt5WnqTBc95" }], "nextCursor": "eyJpZCI6…" }

Filter by a field's name, with commas for several values, like status=pending,approved. Every list also takes createdAfter and createdBefore. The SDK's paginate walks every page for you.

Most objects aren't deleted. Set their status to archived instead; lists leave archived objects out unless you filter for them.

Updates

PATCH changes only the fields you send. To make sure nobody changed the object since you read it, send its version; if it's stale you get 409 version_conflict, and you read it again.

Idempotency

Send an Idempotency-Key header on a write you might retry. A retry with the same key returns the first response instead of writing twice. Writes that move money require one: payments, retainer offers and withdrawals.

Errors

A failed request returns a problem with a stable code to branch on, a readable detail, and a fix when there's a clear next step:

JSON
{
  "status": 422,
  "code": "invalid_request",
  "detail": "type: expected one of \"organic\"|\"paid_ads\"",
  "fix": "Fix `type` in the request body.",
  "retryable": false,
  "errors": [{ "field": "type", "message": "Expected one of \"organic\"|\"paid_ads\"" }]
}
StatusMeans
401Missing, invalid or expired key or token
403The key can't do this, or can't reach that account
404Not found, or not visible to this key
409A conflict, or a setup step left first (requirement_… codes)
422Invalid request; its errors array lists every bad field
429Rate limited; wait Retry-After seconds

retryable says whether sending the same request again can succeed. Every problem also has a requestId; include it when you contact support.

OpenAPI

The full OpenAPI document is at https://api.onlucra.com/v1/openapi.json. Every endpoint, with its fields, is in All endpoints.