Lolly
افتح التطبيق

Move from a hosted render API

ملاحظة: Lolly Work

This guide covers the optional organisation service. Configuration, console and API paths refer to your Lolly Work instance. The packaged console keeps its release-matched copy of this guide.

This page is for the developer or admin who renders images through Bannerbear or Placid and wants to run that production on a server of their own. A hosted service can stay in place while you test the move, you can move one template at a time, and leaving stays open in both directions.

Note: Built from public documentation, never run against a live account

Every adapter on this page comes from each vendor's public documentation and from fixtures built from those docs. None has been run against a real Bannerbear or Placid account. If you hold an account, the check list takes under an hour, and it is the check that counts for your move.

Lolly and rendering APIs compares the services. This page is the how.

What each source allows

The move follows the same stages as leaving a DAM: connect, pin, recreate, compare, run side by side, then cut over. How much carries across depends on what the vendor's API returns.

Bannerbear V5Bannerbear V2Placid
Template listNames, tags, size, preview and the full layer designNames, tags, size, preview and field namesNames, tags, thumbnail, and layer names and types
The design itselfImports as an editable Design documentRebuilt against a referenceRebuilt against a reference
SizeGivenGivenNot given: a reference render shows the size
Image requestsYes, on /compat/Yes, on /compat/Yes, on /compat/
Waiting for a resultSync host, 10 second limitSync host, 10 second limitcreate_now
Per-request webhookThe API has nonewebhook_urlwebhook_success
Dynamic image URLsNot supportedNot supported/u/{uuid} with its signatures

Connect

Read the account, with no Lolly Work server involved. Nothing is written to the account.

export BANNERBEAR_KEY=...
lw render-api inventory --from bannerbear-v5 --token-env BANNERBEAR_KEY --out ./move

--from takes bannerbear-v5, bannerbear-v2 or placid. The key is read from the environment variable you name, goes only to the vendor's API host, and is never printed. The folder holds:

Pin

Keep what you would miss after the account ends. The inventory folder is the start. To keep a real render as a reference, use sample, which asks the vendor to render and so spends credits on your account. It refuses to run without --spend-credits.

lw render-api sample --from placid --template ospo24ysn --token-env PLACID_KEY \
  --values request.json --out ./move/references --spend-credits

request.json is the body you would send the vendor. Re-run inventory on a cadence while you move, and compare the folders to see what changed upstream.

Recreate the design

Bannerbear V5. The API returns the design, so bring it in:

lolly import ./move/templates/6EZ9nQX0lzpWwqAgzB.json --output=design.json --mapping=mapping.json

You can also open the JSON in Design Import. Text, rectangles, circles and image containers become editable layers, and the report names everything left out. Check the result against the preview, then make it a tool with Share with rules. --mapping writes the entry below with the final input ids, so prefer it to the draft for this source.

Bannerbear V2 and Placid. Their APIs return field names and a preview, not a design, so nothing can import the layout. Rebuild each template as a tool, by hand or with an agent, with the preview in view. Keep one input per field in coverage.md.

Tools are the part worth taking time over. A rebuilt tool can use your design system's colours, type and rules, and its inputs can be locked or limited by policy.

Map the template

A mapping says which tool serves a vendor template, and which input each vendor property fills. Review it like a delivery destination, because it decides what callers can change.

{
  "templates": [
    {
      "source": "placid",
      "template": "ospo24ysn",
      "toolId": "link-card",
      "format": "png",
      "layers": {
        "title": { "text": "heading" },
        "subline": { "text": "body" },
        "img": { "image": "image" }
      },
      "ignore": ["title.text_color"],
      "fixed": { "siteName": "Example" }
    }
  ]
}

A property the mapping does not name is refused by name, with 422 PROPERTY_NOT_MAPPED and the list. Nothing a client sends is dropped silently, so a surprise shows up as an error during testing rather than as a wrong image later.

Check a mapping against this instance before you rely on it:

lw render-api check --mapping mapping.json

It reads each tool's effective schema and reports an input that does not exist, an input policy has locked, or a format this deployment cannot make. It exits 2 if any template cannot run.

Compare before you cut over

Measure a render here against the vendor's reference, with the same production comparison a durable render can use.

lw render-api compare --from placid --mapping mapping.json --template ospo24ysn \
  --reference ./move/references/ospo24ysn.png --values request.json --regions regions.json

The command prints each check and exits 2 when the render differs, naming the region that moved. It renders in the reference's own size and format, and the reference must be a PNG or JPEG of at most 675,000 bytes. A match measures pixels against this reference. It is not an approval of the design.

Run both, then cut over

The migration API is off by default, and every /compat/ route then answers 404. Turn it on in the instance configuration:

{
  "renderApi": {
    "enabled": true,
    "mappingsFile": "/etc/lolly-work/render-api-mappings.json",
    "resultUrls": { "signedDays": 30 }
  }
}

Set LW_RENDER_API_URL_SECRET as well, for result URLs. Then change the base URL and the token in your client. The request and response shapes stay the same.

Your client callsChange the base to
https://api.bannerbear.com/v5/imageshttps://work.example.com/compat/bannerbear/v5/images
https://sync.api.bannerbear.com/v5/imageshttps://work.example.com/compat/bannerbear/sync/v5/images
https://api.bannerbear.com/v2/imageshttps://work.example.com/compat/bannerbear/v2/images
https://sync.api.bannerbear.com/v2/imageshttps://work.example.com/compat/bannerbear/sync/v2/images
https://api.placid.app/api/rest/imageshttps://work.example.com/compat/placid/api/rest/images
https://api.placid.app/u/{uuid}https://work.example.com/compat/placid/u/{uuid}

Authentication is the same header, Authorization: Bearer, carrying a service token with the render scope. A person's session is refused. Everything runs as a durable render, so tool visibility, input policy, validation and audit apply, and a locked input is refused at submission with INPUT_LOCKED. Every response keeps the vendor's fields and adds a lolly member with the record id and render ids.

Move one template at a time, because a template that has no mapping answers 404 here while the vendor keeps serving that template. Send each client to whichever host holds its template, and keep the vendor account until the last one has moved and the references are safe.

What runs and what is refused

RequestHere
Bannerbear V5 formatsOne durable render per format under one record. webp and avif are refused by name
Bannerbear V5 scale, dpi, quality, proxy, versionMap them to an input or list them under ignore. scale: 1 needs neither
Bannerbear V5 registered webhooks501: their payload and signature could not be confirmed. Use callbackUrl on a native render
Bannerbear V2 render_pdfA second render, polled as pdf_url. With webhook_url it is refused, because two renders cannot announce themselves as one webhook
Placid transferRefused: use a delivery destination
Placid modifications.image_formatjpg, png and auto work. webp is refused by name
Placid modifications.width, height, dpiMap them to an input or list them under ignore
Anything else on those hosts: animations, videos, PDFs, collections, screenshots, tools, template editing501 with the reason

Formats depend on the deployment: JPG and PDF need the render worker.

Webhooks

webhook_url and webhook_success post the vendor's object when the render finishes, through the same durable outbox as native callbacks, with the same retries. A failed render sends the object too, with its failed status.

Result URLs

Clients built for hosted APIs store a result URL and embed it, so image_url and files hold signed URLs that need no token. This is a tradeoff, and the opposite of what job result tokens do, which moved out of URLs because a URL ends up in logs.

Output retention, when configured, also ends a URL: the file then answers 410.

Placid's URL API

GET /compat/placid/u/{uuid}?title[text]=Hello answers with the image, and the same URL is one render until your design system or catalog changes. Set which service token these renders act as:

{ "renderApi": { "urlApi": { "actAs": "<service token id>" } } }

These URLs keep working. If output retention removes the file, or the stored file is lost, the next request makes a new render and later requests reuse that one. A failed render answers 502 for a minute, then the next request tries again. These renders run at normal priority, so under load a URL can answer 503 with Retry-After while the render finishes.

Existing signed URLs keep working with a host change alone, if you give the template the old private token:

{ "source": "placid", "template": "ospo24ysn", "toolId": "link-card", "format": "png",
  "layers": { "title": { "text": "heading" } },
  "url": { "credentialRef": "PLACID_PRIVATE_TOKEN" } }

credentialRef is the name of the environment variable. An unsigned URL is refused unless the template sets "allowUnsigned": true, because anyone could then make the server render. Placid's example signs a query string starting with &, and its documentation does not say whether that character is part of the contract, so both forms verify. A proxy that re-encodes the query will break a signature.

Bannerbear's signed base URLs and Instant URLs are not supported, because their signing could not be confirmed from public documentation.

Leave Lolly too

Nothing here is one-way.

Your vendor account also stays yours for as long as you keep the account open. Moving some templates and keeping others is a fine place to stop.

Check it on your own account

If you hold an account, this confirms the adapter for your templates. Use a template you can spare, and note that steps 2 and 4 spend credits.

  1. Run inventory. Read coverage.md: does every layer you use appear, with the type you expect?
  2. Run sample on one template, then send the same body to /compat/. Do the responses have the same fields?
  3. For Bannerbear V5, run lolly import and open the result. Do positions and sizes match the preview? The docs give no units or paint order, so these are the first things to check.
  4. Send a request with a webhook to a receiver you control. Is the body the same shape as the vendor's?
  5. For Placid, sign a URL the way your code does, and request it from /compat/placid/u/. Does it verify?

Tell us what you find with an issue. Please leave out your key, and any customer data in the requests.

Bannerbear and Placid are trademarks of their owners. This page describes how to move work between products and is not affiliated with either.