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>.

POST /api/v1/announcement-bar animated GIF cached by config
inbox preview

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.

FREE SHIPPING ON $50+ • USE CODE SAVE20 • ENDS SUNDAY

Classic dark

The default look — three offers, bold sans, dot separators.

boldsep dotspeed medium600×50
SUMMER SALE • UP TO 50% OFF • TODAY ONLY • SHOP NOW

Festive, four messages

High-energy red with star separators, faster scroll.

4 textssep starspeed fastsmooth high
Free returns within 30 days

Single message, serif

Light theme, one reassurance line, slow and calm.

serifsep diamondspeed slowlight
New arrivals just dropped   Members get 15% off

Italic, no separator

Spacing-only rhythm between messages on deep blue.

italicsep none600×50
DROP 06.01 • EARLY ACCESS

Mono, leaderboard size

Monospace drop teaser at 728×90 with a custom integer speed and plus separators.

monosep plusspeed 100728×90

Reference

Endpoint

Deterministic block: POST a JSON config and receive a hosted GIF URL. Identical configs return the same URL with cached: true.

POST https://blocks-api-production.up.railway.app/api/v1/announcement-bar
POSTrequest · application/json
{
  "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
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.

FieldTypeDefaultRules
textsrequiredstring[]1–4 items, each non-empty, ≤ 40 chars.
backgroundColorstring#0A0A0AHex #RGB or #RRGGBB.
fontColorstring#FFFFFFHex #RGB or #RRGGBB.
fontStyleenumboldregular · bold · italic · serif · mono
separatorenumdotdot · diamond · line · slash · plus · star · none (drawn shapes)
speedenum | intmediumslow · medium · fast (45/80/130 px/s) or an int 10–400.
smoothnessenummediumlow · medium · high — frame density vs file size.
widthint600100–1200. Standard email body width.
heightint5024–120.

200 OK

Response

Returns the hosted GIF plus its dimensions and size. The url is what you embed.

response · application/json
{
  "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.
  • cachedtrue if 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.

HTML
<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.