Service & auth
| Method | Path | Purpose |
|---|---|---|
| GET | /v1 | Service metadata and the public route inventory |
| GET | /v1/scopes | Scope taxonomy, bundles, and wildcard rules (public) |
| GET | /v1/mcp/tools | MCP tool catalog with schemas and statuses (public) |
| POST | /v1/auth/introspect | Verify a bearer token and return its principal |
| GET, POST | /mcp | MCP JSON-RPC endpoint |
Every response wraps its payload in the standard envelope — the JSON examples below show the contents of data. Errors follow the shape in Errors & limits.
Organization profile
GET /v1/organization/profile
Roles: Owner or Admin.
{
"organization": {
"id": "acme",
"slug": "acme",
"name": "Acme",
"imageUrl": "https://cdn.onlucra.com/logos/acme.png",
"partnerEnabled": false
}
}
PATCH /v1/organization/profile
All fields optional; unknown fields are rejected. Invite links are never readable or writable through the API.
| Field | Type | Notes |
|---|---|---|
name | string | Max 160 characters |
imageUrl | string | HTTPS URL for the logo |
Returns the updated { "organization": ... }.
Programs
GET /v1/programs
Any workspace role. Returns { "programs": [...] } — the workspace's programs as shown on the Programs page, each with its identity, status, visibility, terms, and submission activity. Partners can scope to a client with ?client={brandSlug}.
POST /v1/programs
Roles: Owner or Admin. Send JSON, or multipart/form-data with a payload field carrying the JSON below plus briefFiles uploads (PDF, DOC, or DOCX — up to 10 files, 15 MB each).
Required fields:
| Field | Type | Notes |
|---|---|---|
name | string | Max 160 characters |
programType | string | "paid_ads" or "organic" |
visibility | string | "invite_only" or "open" — open programs go Live on creation; invite-only start as drafts |
welcomeMessage | string | The note creators see before submitting |
acceptedPlatforms | string[] | "tiktok" / "instagram", max 2 |
allowPaidPromotion | boolean | Enables Spark/Partnership paid usage |
allowManualOrganicUpload | boolean | Organic programs: allow manual uploads |
briefFileNames | string[] | Names of attached brief files (may be empty) |
Optional fields: maxSubmissionsPerCreator (1–10) · approvedSubmissionFeeCents · budgetCents · paidCreatorPayoutCapCents · organicCompensationMode ("cpm" or "fixed_per_post") · organicCpmCents · organicFixedPostCents · organicMaxPayoutCents · promotedProducts[] · promotedObjectType / promotedObjectName / promotedObjectUrl. Paid-ad programs and organic programs with paid promotion also require paidCompensationMode: "ad_spend_share" and an explicit paidCompensationBps (1–10000).
Response 201:
{
"program": {
"id": "spring-creator-spark",
"name": "Spring Creator Spark",
"status": "Live",
"budget": "$5,000"
}
}
PATCH /v1/programs/{programId}/creators/{reviewId}
Roles: Owner or Admin. Decides a creator's application to the program.
{ "status": "Approved" }
status is "Approved", "Rejected", or "Applied". Response:
{
"review": {
"id": "rev_123",
"creatorName": "Jordan Lee",
"creatorEmail": "[email protected]",
"programName": "Spring Creator Spark",
"status": "Approved"
}
}
Submissions
Submissions are created by creators in their portal — the API lists and reviews them.
GET /v1/creatives
Any workspace role. Returns { "items": [...] }. Each submission includes:
id,status(Review·Revision·Approved·Live·Rejected),statusUpdatedAt, andstatusHistory(every change with who made it and any note)campaign(the program name),submittedAt,creatorName,creatorAvatarSrc- media:
videoSrc,thumbnailSrc,duration,format,sourceUrl,sourcePlatform transcriptandtranscriptStatus- legacy TikTok Spark authorization metadata when present on historical submissions
GET /v1/creatives/{creativeId}
Returns { "item": ... } with the same shape; 404 if not found.
PATCH /v1/creatives/{creativeId}
Roles: Owner or Admin. The review decision:
{ "status": "Revision", "note": "Trim the intro to three seconds." }
status accepts "Approved", "Revision", "Rejected" (plus "Review" and "Live" for requeueing and launch tracking); note is optional, max 2,000 characters. Returns the updated { "item": ... }.
Paid campaigns
GET /v1/paid-campaigns
Returns { "campaigns": [...] } — every non-archived campaign. Campaign objects carry: identity (id, name, status, platforms, createdAt, updatedAt), objective and destination (objective, destination, destinationValue, per-platform app and pixel ids), audience (audienceCountryCodes, audienceAgeMin/audienceAgeMax, audienceGender), budget and schedule (budgetMode, dailyBudgetCents, lifetimeBudgetCents, billingLimitCents, startDate, endDate), ad text (adPrimaryText, adHeadline, callToAction), the payoutRule, attached creatives (with creator name and media), and per-platform platformLaunches and platformCreativeMappings.
POST /v1/paid-campaigns
Roles: Owner or Admin. Creates a draft campaign.
Required fields:
| Field | Notes |
|---|---|
name | At least 2 characters |
platforms | ["meta"], ["tiktok"], or both |
objective, destination, destinationValue | Campaign objective and landing destination |
adPrimaryText, callToAction | CTA values like "learn_more", "shop_now", "download" |
audienceCountryCodes | e.g. ["US"] |
audienceAgeMin, audienceAgeMax | 18–65 |
budgetMode | "daily" with dailyBudgetCents, or "lifetime" with lifetimeBudgetCents |
startDate | ISO date |
creativeAssetIds | 1–100 approved submission ids |
payoutRule | See below |
{
"payoutRule": {
"mode": "ad_spend_percentage",
"percentageBps": 950,
"creatorBps": 750,
"platformBps": 200,
"creatorPayoutCapCents": 50000
}
}
Conditionally required: app destinations need metaPromotedAppId / tiktokPromotedAppId; pixel-tracked conversion objectives need metaPixelId / tiktokPixelId and tiktokOptimizationEvent. Optional: adHeadline (≤80), audienceGender, billingLimitCents, endDate, notes, tiktokLocationIds, tiktokIdentityDisplayName, tiktokIdentityImageUrl.
Response 201: { "campaign": ... } with "status": "draft".
GET / PATCH / DELETE /v1/paid-campaigns/{campaignId}
GET returns { "campaign": ... } (404 if missing or archived). PATCH accepts a status-only body — { "status": "live" } with "draft" · "ready" · "live" · "paused" · "archived" — or a full campaign update; setting a campaign live requires at least one attached creative. DELETE archives the campaign.
POST /v1/paid-campaigns/{campaignId}/creatives
{ "creativeAssetId": "crv_123" }
Attaches an approved submission; returns the updated { "campaign": ... }.
DELETE /v1/paid-campaigns/{campaignId}/creatives/{creativeAssetId}
Detaches the submission; returns the updated { "campaign": ... }.
Creators
GET /v1/creators
Any workspace role. Returns { "items": [...] } — the creators connected to your workspace, including represented creators, with their program associations. Each row includes: id, name, email, handle, platformHandles, avatarSrc, initials, status, tags, campaigns (the programs they're in), approvedVideos, pendingVideos, approvalRate, installs, lastActive, location, bio, specialty, audience, referenceVideos, retainer (when set: monthly fee, deliverables, start/end), source, and createdAt. Creator records are read-only through the API.
GET /v1/creators/{creatorId}
Returns { "item": ... } with the same shape; 404 if the creator is not on your roster.
GET /v1/explore/creators
Any workspace role. The full Explore marketplace listing. Without query params the complete list is returned; pass limit and/or offset to paginate:
curl "https://api.onlucra.com/v1/explore/creators?limit=25&offset=50" \
-H "Authorization: Bearer $LUCRA_API_TOKEN"
| Param | Notes |
|---|---|
limit | 1–100, defaults to 25 when paginating |
offset | 0 or greater, defaults to 0 |
{
"creators": [
{
"name": "Jordan Lee",
"headline": "UGC for consumer apps",
"profileSlug": "jordan-lee",
"handle": "@jordanmakes",
"categories": ["apps", "lifestyle"],
"location": "Austin, TX",
"connected": false,
"requestStatus": null,
"approvalRate": "92%",
"referenceVideoSelections": [],
"trustProfile": { "trustScore": 72 }
}
],
"pagination": { "hasMore": true, "limit": 25, "offset": 50, "total": 132 }
}
The pagination object is included only when limit or offset is passed.
This is the complete public surface — the API is intentionally small. Creator self-service, partner delegation, finance, billing, invites, integrations, samples, and everything else the Lucra apps do run through internal routes that are not reachable from the public API and can change without notice.
