/v1 API, so the same loop works whether you’re a remote MCP client or calling HTTP directly.
The loop closes on itself: a result that isn’t good enough feeds back into a bounded refine pass, and a workspace that runs out of credits gets a one-tap top-up — so the agent never dead-ends.
The Guarantees
Two hard rules hold across the whole loop. Rely on them:No card entry in chat
Credit top-ups always return a Stripe-hosted checkout link. The agent never asks for, collects, or handles card details — the user pays on Stripe’s page and the credits land on the workspace.
Loops are cost-capped
The refine loop never spends past
maxCredits. It stops the instant the score clears the bar, the iteration cap is hit, or the next attempt wouldn’t fit the budget — whichever comes first — and reports exactly what it cost.The Loop, Step by Step
1
Discover an app
Find an app that fits the intent.
lamina_discover (MCP) or GET /v1/apps. Each app has a typed, discoverable input contract — inspect it with lamina_describe / GET /v1/apps/{appId} before calling.Prefer one-call creation (POST /v1/content/create) when you want the engine to pick the app and map inputs for you.2
Estimate the cost, and top up if needed
Check the balance and what a run will cost before committing. Hand the user the
lamina_credits returns { balance, packages[] }; POST /v1/apps/{appId}/estimate returns a per-node cost breakdown.If the balance is short, don’t dead-end — start a top-up:checkoutUrl. Once they pay, the credits land on the workspace and you retry the run. Never ask for card details — that’s what the Stripe page is for.If a generate/run does fail for credits, the error comes back structured — the exact shortfall, a suggestedPackage, and a topUp hint — so you can say “you need N more credits, top up here” and continue.3
Generate
Run the app:
lamina_run (app workflow), lamina_generate_image / lamina_generate_video (atomic), or POST /v1/apps/{appId}/runs. Runs are async and return a runId immediately.Poll with lamina_status / GET /v1/runs/{runId}, or use wait: true to block server-side until terminal. Most apps finish in 1–5 minutes.4
See the result inline
lamina_status returns generated images inline as MCP image blocks, so the assistant renders them in-chat — the full-resolution URL is always in the JSON too.For video, the status carries output.poster — a still preview frame the assistant shows inline — alongside the durable, playable video link. Output URLs are long-lived public links you can hand the user to open later.5
Score and take the approve / reject turn
Before showing the result as final, check how on-brand it is:
lamina_brand_compliance— read the Brand Guard result the run recorded (per-node status + score), when Brand Guard was enabled on the app.lamina_brand_score— score any completed run’s image on demand (Brand Guard on or off), returning abrandFit(0–100), the specificdeviations, andsuggestions.
lamina_brand_feedback with the reason — it becomes a brand guardrail the next generation avoids, closing the loop.6
Refine within budget
If it’s close but not there, let Lamina improve it automatically — capped:This repeats score → refine (re-rolling with the deviations fed back in) and stops the instant Defaults:
brandFit >= minScore, iterations >= maxIterations, or the credit budget would be exceeded — whichever comes first. It returns the best result plus a plain-English summary:minScore 80, maxIterations 3, maxCredits 200. Per-attempt and cumulative cost are in attempts[], so you can always tell the user exactly what a refine cost.7
Deliver the artifact
Hand over the best result’s durable URL (and, for video, the poster). The link is a long-lived public URL the user can open any time.Want it published to a channel instead?
POST /v1/publishing/publish.