# Changelog

> New features, improvements and fixes to the Lucra API, newest first.

Source: https://www.onlucra.com/docs/what-changed

New features, improvements and fixes to the Lucra API, newest first. Everything here ships under `Lucra-Version: 2026-10-01`, the one API version. Changes are additive unless they're listed under **Breaking changes**, which always come with what to use instead.

## October 30, 2026

**New: read changed rows by ID.** Applications, campaigns, creators, earnings, products, programs, samples and submissions take `ids`, up to 100 comma-separated IDs, to read exactly those rows. Use it to refresh only what a webhook named. A wrong kind of ID, or more than 100, is a `422`. See [Lists](https://www.onlucra.com/docs/api-introduction#lists).

**Changed: accounts you create get only payment and sign-in emails.** Accounts you create get emails from Lucra only for payments and sign-in; everything else is in-app — you tell them. This covers brands from `POST /v1/brands` and creators from `POST /v1/creators`, made with a key or in the Lucra app, and stays so after they sign in themselves. See [Partners](https://www.onlucra.com/docs/api-partners#what-your-key-reaches).

**Changed: API invites return a link; Lucra doesn't email from the API.** A call with an API key, OAuth token or embed never makes Lucra send an email. `POST /v1/creators` returns `inviteUrl` for a creator it invites, for you to share. Notices your calls cause, such as a creator's request from `POST /v1/marketplace/requests`, still show in Lucra and on push, but aren't emailed. See [Add a creator to your roster](https://www.onlucra.com/docs/api-creators#add-a-creator-to-your-roster).

**Improved: embeds update live.** [Embeds](https://www.onlucra.com/docs/embeds) refresh the rows that changed as soon as they change, including changes made through the API, without reloading.

## October 29, 2026

### Breaking changes

These are the only changes in this release that can break an existing request or reader. Everything else is additive.

| Change | What to do |
| --- | --- |
| **Ad templates are removed**: `GET`/`POST /v1/ad-templates`, `GET`/`PATCH /v1/ad-templates/:id`, `template` on campaigns, campaign drafts and `POST /v1/campaign-validations`, and the MCP tool `ad_templates_find`. | Set what new campaigns start with in [ad defaults](https://www.onlucra.com/docs/api-ads#ad-defaults) (`GET`/`PATCH /v1/ad-defaults`). |
| **Copy endpoints are removed**: `POST /v1/campaigns/:id/copies`, `POST /v1/ad-sets/:id/copies`, `POST /v1/ads/:id/copies`, the copy endpoints under `/v1/connections/:id/platform-campaigns`, the `copy_campaign` fix's `request`, and the MCP tools `ads_copy` and `outside_campaigns_copy`. | Read the original (`GET /v1/campaigns/:id`), then create a new one with `POST /v1/campaigns` and `status: "draft"`. |
| **`partnerApproval` is removed from campaigns.** It was always `null`; there's no approval step. | Read `job` for the change that's running. |
| **`listing` is removed from creators.** It was documented but never sent. | Use `GET /v1/marketplace/creators`. |
| **`holdUntilAt` is removed from payments.** A disputed payment is held until the dispute closes, which has no set date. | Read `status` and `dispute`. |
| **`objective` and `destination` can be `null` on campaigns.** They're `null` on campaigns with `source: "platform"`, which bill matched outside ads that mix objectives. | Handle `null`, or skip campaigns where `source` is `platform`. |

### Access for partners

**New: see what you can do before you call.** `GET /v1/brands` returns each client's `relationship` with its `grants` and a `can` object, and `GET /v1/account` returns `can` for the account you act in. Each endpoint declares the [capability](https://www.onlucra.com/docs/access) it needs (`x-lucra-capability` in the OpenAPI document).

**Changed: client access is a set of grants.** A brand switches individual grants on or off for its partner. Every client relationship, new or existing, starts with every grant on, so nothing you could do before is taken away. You run every client like the brand itself, money included, whether you created it or the brand invited you. `relationship.managed` still says whether you created the brand, but no longer limits access. See [Partners in a client brand](https://www.onlucra.com/docs/access#partners-in-a-client-brand).

**Improved: clearer refusals.** A `403` keeps its code and adds `reason`, plus `capability` and `grant` when the client's access refused it, so you can tell the person exactly what to switch on. A few actions only the brand can take, such as deleting the account, changing its partner's grants, inviting partners and creating brands, answer `403 own_account_only`. See [Refusals](https://www.onlucra.com/docs/access#refusals).

### Ads and analytics

**New: add to a running campaign.** `POST /v1/ad-sets` adds an ad set, with its ads, to a campaign, and `POST /v1/ads` adds an ad to an ad set. See [Ad sets and ads](https://www.onlucra.com/docs/api-ads#ad-sets-and-ads).

**New: ads you run yourself are credited.** Lucra matches every ad in a connected ad account to the Lucra video it runs, on exact evidence only: the `lucra_id` in its link, the Lucra ID in its name, the platform's ID of a video Lucra uploaded, the file itself, or the creator's post. A match waits three days in review. After that, a creator's approved work bills like an ad Lucra launched, and the brand's and partner's own uploads are report-only. Each submission's `tracking` is the parameter to add to any landing URL. See [Ads Lucra didn't launch](https://www.onlucra.com/docs/api-ads#ads-lucra-didnt-launch).

**New: platform metrics in analytics.** `GET /v1/analytics?include=platform` adds `platformMetrics` to each row: every metric the platform reports for that ad, whether Lucra launched it or not. See [Platform metrics](https://www.onlucra.com/docs/api-ads#platform-metrics).

**New: more analytics.** `groups` returns one row per group over the whole range, `metrics` describes every metric with its label and unit, and rows gain derived results (`results`, `roas`, `ctr`, `cpc`, `costPerResult` and more), video and engagement metrics, and fee columns (`lucraFee`, `partnerFee`, `creatorRewards`, `processingFee`, `charged`). A metric no platform in the rows reports is `null`. See [Analytics](https://www.onlucra.com/docs/api-ads#analytics).

**New: campaign drafts.** `POST /v1/campaigns` takes `status: "draft"`, and its ad sets and ads take their own `options`. Campaigns gain `source`: `lucra`, or `platform` for the campaigns that bill matched outside ads.

**Changed: platform names carry the Lucra ID.** Campaigns, ad sets and ads Lucra creates on a platform now end with ` · L:` and the object's Lucra ID (`L:camp_…`, `L:adset_…`, `L:ad_…`), so you can find them in an ads manager. Older objects keep their previous tag. If your automation parses these names, read the Lucra ID. An ad name template no longer needs `{asset_id}`.

**Fixed: real values everywhere.** Ads Lucra didn't launch report their real `status`, `review` and matched video instead of `unknown`. Campaigns an ad account runs report their real objective, end date, audience, bidding, budget and results, and keep changes you `PATCH`. Ad accounts report their real last sync time and sync error. Meta `purchases` count purchases only; leads are in `leads`.

### UTC days from October 31

**Changed: every day is a UTC day.** From 2026-10-31 00:00 UTC, every day of spend and results is a UTC day: ads, analytics, settlement and monthly fees. Days before that stay each ad account's own calendar day, and the day that crosses the switch keeps only its hours before it, so no hour counts twice. From then on, count "today" in UTC.

### Payments and earnings

**New: what each video earned.** Every submission returns `paidOut`, what its creator was paid for it, and `adSpend`, the ad spend on it from Lucra's ads and matched outside ads. See [Submissions](https://www.onlucra.com/docs/api-submissions#review).

**New: earnings totals.** `GET /v1/earnings` returns `earned`: what the creator earned in total, per program and per submission, whatever the filters and page. Show it instead of adding up pages. See [Earnings](https://www.onlucra.com/docs/api-payments#earnings).

**New: withdrawal quotes.** `GET /v1/balance?amount=` returns what a withdrawal of that amount costs at each speed, fee by fee, exactly as it will be taken. `GET /v1/balance` returns one row per currency the payout balance holds, US dollars first, and `POST /v1/withdrawals` takes that `currency`. New errors: `409 withdrawal_instant_currency_unsupported` and `409 withdrawal_blocked_by_clawback`. See [Withdrawals](https://www.onlucra.com/docs/api-payments#withdrawals).

**New: save a card without leaving your app.** `POST /v1/connections` with `card` still returns the hosted page at `url`. You can also save the card inside your app with the `onboarding` embed, or build your own card form with the returned client secret. See [Save a card](https://www.onlucra.com/docs/api-connections#save-a-card).

**Fixed: held earnings.** A held earning's `holdUntilAt` is `null` while it waits on a dispute or on the payment it comes from, instead of a far-future date. Balance `crossBorder` and `tax.required` follow the payout account's real country.

### Partner fees

**New: dated fee terms per client.** A partner's [`fees`](https://www.onlucra.com/docs/api-brands#fees) on a client are a percent of ad spend plus a fixed amount per approved creator video, from an `effectiveOn` day. The earliest is tomorrow (UTC), given as `earliestEffectiveOn`; an earlier day is `422 fees_effective_on_past`. Changes are added to the history and never edit it. `brandFee` keeps working and reads the percent in force today; new code should use `fees`.

**Changed: what each fee is charged on.** The per-video fee is charged once per approved creator video, revisions included, and is reversed only if the charge for it is refunded or lost in a dispute. From spend day 2026-10-31, Lucra's fee on revenue-share campaigns is charged on ad spend, not attributed sales, and a partner's percent also applies to report-only outside ads of the brand's or partner's own uploads (with no Lucra fee and no creator pay). The 1.50% fee on flat payments to creators is unchanged. See [Pricing & billing](https://www.onlucra.com/docs/billing).

**Changed: payouts aren't needed to launch.** A partner without a verified payout account can launch campaigns in a client. It sets up payouts when it wants to withdraw.

### Metadata

**New: your own metadata.** Campaigns, ad sets, ads and programs take `metadata`, your own string keys and values, on create and `PATCH`; payments and brands take it on `PATCH`. Filter their lists with `metadata[key]=value`. A partner's metadata on a client brand is the partner's own: the brand doesn't see it. See [Objects](https://www.onlucra.com/docs/api-introduction#objects).

### Webhooks

**New: `brand.updated`.** Partners hear when a client brand changes. Every key with a webhook URL receives every event type, so ignore the types you don't handle. See [Webhooks](https://www.onlucra.com/docs/webhooks).

**Improved: events name the creator.** `payment.failed`, `payment.refunded`, a retainer's past-due charge and `submission.live` now name the creator involved.

### Sandbox and keys

**Changed: the sandbox runs real payment flows.** The [sandbox](https://www.onlucra.com/docs/sandbox) runs the same code as live, with simulated ad platforms and test money. Cards, charges, payouts and withdrawals follow live's rules, including who can add a card. Add a card and set up payouts again with the [sandbox test values](https://www.onlucra.com/docs/sandbox#test-values); the sandbox's old placeholder cards and payout accounts are gone. Ad accounts connected before this change need to reconnect once.

**New: run a job now.** `POST /v1/sandbox/runs` runs a spend sync or a collection immediately instead of waiting for the schedule. Live answers `404`.

**New: `lucra_test_` keys.** Sandbox keys start with `lucra_test_` (older `lucra_sandbox_` keys still work). A live key used against the sandbox, or a test key used against live, answers `401 invalid_key` and names the key to create.

**New: SDK 1.0.** [`@lucra/sdk`](https://www.onlucra.com/docs/sdk) 1.0 is generated from the OpenAPI document. It picks the API host from the key, so a test key never reaches live, and `LucraError` carries `reason`, `capability` and `grant`.

### Errors and reliability

**Improved: every error tells you how to fix it.** Problems use plain wording with a `fix`, and every response carries `X-Request-Id` to quote to support. Responses that gather several parts list any part that didn't load in `unavailable` instead of failing the whole request. See [Parts that didn't load](https://www.onlucra.com/docs/api-introduction#parts-that-didnt-load).

**Fixed: concurrent campaign saves.** Two partners saving the same campaign at once get `409 campaign_partner_conflict` instead of a server error.

### Still supported

These older fields keep working, so existing integrations don't need to change:

- `brandFee` on `/v1/account` and `/v1/brands` reads and writes the percent part of the dated fees.
- `pendingChange` on campaigns shows the change the platform is running. `PATCH` with `pendingChange: "approved"` answers `409 campaign_no_pending_change`.
- `settings.creator: null` on campaigns and drafts is accepted and ignored.
- `balance` on transactions is the prepaid-credit balance after the line, `null` on newer lines.
- `expiresAt` on `PATCH /v1/ad-authorizations` is accepted and ignored.

## October 27, 2026

### Ads rebuilt

**Improved: a rebuilt ads engine.** Requests that worked before still work, and responses carry more: `job`, `issues`, `options`, `storedStatus` and platform IDs on campaigns, ad sets and ads. Problems from a platform carry `issues[]` with the fix. See [Ads](https://www.onlucra.com/docs/api-ads).

**Changed: a few meanings.**

- `billingLimit` caps creator pay and fees billed through Lucra, not ad spend. `null` removes it.
- Meta ad access moved from `POST /v1/ad-authorizations` to a program's creator approvals (`approvals` on `GET /v1/applications`). Ad authorizations are TikTok Spark codes.
- `GET /v1/ad-fields` keys are option keys (`meta.bidStrategy`), the same ones `options` takes.
- `status: "archived"` on an ad set or ad removes it from its campaign and from the platform.

**New: error codes.** `ad_resource_removed`, `creator_not_authorized`, `platform_refused` and `provider_unavailable`.
