API reference

Endpoint reference

Service & auth

MethodPathPurpose
GET/v1Service metadata and the public route inventory
GET/v1/scopesScope taxonomy, bundles, and wildcard rules (public)
GET/v1/mcp/toolsMCP tool catalog with schemas and statuses (public)
POST/v1/auth/introspectVerify a bearer token and return its principal
GET, POST/mcpMCP 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.

FieldTypeNotes
namestringMax 160 characters
imageUrlstringHTTPS 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:

FieldTypeNotes
namestringMax 160 characters
programTypestring"paid_ads" or "organic"
visibilitystring"invite_only" or "open" — open programs go Live on creation; invite-only start as drafts
welcomeMessagestringThe note creators see before submitting
acceptedPlatformsstring[]"tiktok" / "instagram", max 2
allowPaidPromotionbooleanEnables Spark/Partnership paid usage
allowManualOrganicUploadbooleanOrganic programs: allow manual uploads
briefFileNamesstring[]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, and statusHistory (every change with who made it and any note)
  • campaign (the program name), submittedAt, creatorName, creatorAvatarSrc
  • media: videoSrc, thumbnailSrc, duration, format, sourceUrl, sourcePlatform
  • transcript and transcriptStatus
  • 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:

FieldNotes
nameAt least 2 characters
platforms["meta"], ["tiktok"], or both
objective, destination, destinationValueCampaign objective and landing destination
adPrimaryText, callToActionCTA values like "learn_more", "shop_now", "download"
audienceCountryCodese.g. ["US"]
audienceAgeMin, audienceAgeMax18–65
budgetMode"daily" with dailyBudgetCents, or "lifetime" with lifetimeBudgetCents
startDateISO date
creativeAssetIds1–100 approved submission ids
payoutRuleSee 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"
ParamNotes
limit1–100, defaults to 25 when paginating
offset0 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.