Nudge Blocks · email render service
Announcement Bar
A scrolling offer bar for the top of marketing emails — rendered to an animated GIF so it works in Gmail, Outlook, and every client that strips CSS animation. Send a small JSON config, get back a hosted URL to drop into an <img>.
Rendered live
Sample bars
Each of these is a real response from the API, served from the GIF host. They animate exactly as they would inside an email.





Reference
Endpoint
Deterministic block: POST a JSON config and receive a hosted GIF URL. Identical configs return the same URL with cached: true.
{
"texts": ["FREE SHIPPING ON $50+", "USE CODE SAVE20", "ENDS SUNDAY"],
"backgroundColor": "#0A0A0A",
"fontColor": "#FFFFFF",
"fontStyle": "bold",
"separator": "dot",
"speed": "medium",
"smoothness": "medium",
"width": 600,
"height": 50
}
curl -X POST https://blocks-api-production.up.railway.app/api/v1/announcement-bar \
-H 'Content-Type: application/json' \
-d '{"texts":["FREE SHIPPING ON $50+","USE CODE SAVE20","ENDS SUNDAY"],"separator":"dot"}'
Request body
Parameters
Keys accept camelCase or snake_case. Unknown fields are rejected with 422.
| Field | Type | Default | Rules |
|---|---|---|---|
| textsrequired | string[] | — | 1–4 items, each non-empty, ≤ 40 chars. |
| backgroundColor | string | #0A0A0A | Hex #RGB or #RRGGBB. |
| fontColor | string | #FFFFFF | Hex #RGB or #RRGGBB. |
| fontStyle | enum | bold | regular · bold · italic · serif · mono |
| separator | enum | dot | dot · diamond · line · slash · plus · star · none (drawn shapes) |
| speed | enum | int | medium | slow · medium · fast (45/80/130 px/s) or an int 10–400. |
| smoothness | enum | medium | low · medium · high — frame density vs file size. |
| width | int | 600 | 100–1200. Standard email body width. |
| height | int | 50 | 24–120. |
200 OK
Response
Returns the hosted GIF plus its dimensions and size. The url is what you embed.
{
"url": "https://blocks-api-production.up.railway.app/blocks/fd3efbb190751372.gif",
"width": 600,
"height": 50,
"bytes": 416378,
"cached": false
}
Fields
- url — hosted GIF for the
<img>src. - width / height — final pixel dimensions.
- bytes — file size on disk.
- cached —
trueif an identical config existed.
Errors
- 422 — validation: empty/>4 texts, text > 40 chars, bad hex, unknown enum or field.
- 413 — rendered GIF over the size cap; reduce width / smoothness.
In the email
Email embed
Drop the returned url into a plain <img>. Set alt to the joined texts so the offer survives image blocking.
<img src="https://blocks-api-production.up.railway.app/blocks/fd3efbb190751372.gif"
width="600"
alt="FREE SHIPPING ON $50+ • USE CODE SAVE20 • ENDS SUNDAY"
style="display:block;border:0;">
Internal use only
Access & security
This service is for Nudge's backend, server-to-server. It is not a public API and should not be reachable by browsers or end users.
Current state: the render endpoint is unauthenticated
Anyone who knows the URL can POST to it. Before sharing it beyond this team, put an API key (or private networking) in front of /api/v1/*. Keep the URL out of client-side code, repos, and emails.
Do
- Call it from the Nudge backend only (server-to-server).
- Add an X-API-Key header check on
/api/v1/*. - Keep
/blocks/*(the GIFs) public — emails must load them. - Rate-limit per key; rely on the built-in input caps (1–4 texts, size limit).
Don't
- Expose the POST endpoint to browsers or third parties.
- Ship the endpoint URL or any key in client-side bundles.
- Publish this page on a public domain (it's marked
noindex). - Pass untrusted end-user text without your own review.
Recommended next step
Add a shared X-API-Key on the render routes (FastAPI dependency, key in an env var) while leaving the GIF host open. That makes the endpoint internal without breaking email delivery.