PromoRails is in testing. Features may change, and payments are in test mode — no real charges are made.Report a problem

PromoRails API

Create banners from your own apps: pick a template, send your texts and image URLs, export, and download the PNGs of every size.

Authentication

Create a key in Account → API keys and send it in the Authorization header. The API acts as your account, with your plan's limits (projects, banners per project, premium templates, watermark on the Free plan). An account has one key: generating a new one revokes the old one.

curl https://promorails.com/api/v1/me \
  -H "Authorization: Bearer pr_your_key"

Base URL: https://promorails.com/api/v1. Requests and responses are JSON. Each key may make 60 requests per minute; the X-RateLimit-* headers show what is left, and a 429 carries Retry-After.

Errors

Errors use HTTP status codes and a body like:

{ "error": { "code": "unknown_field", "message": "values.title: unknown field. Fields: headline, photo." } }

400 invalid request · 401 missing or invalid key · 403 plan limit (project_limit, banner_limit, premium_template, storage_full) · 404 not found · 409 export in progress · 422 an image URL could not be loaded · 429 rate limited.

How it works

  1. GET /templates — choose a template; note its sizes and fields.
  2. POST /projects — create a project with field values and banners, and "export": true.
  3. GET /projects/:id — poll every few seconds until status is completed (or failed); the PNG URLs are in outputs.

Endpoints

GET/templates

Your own templates (My templates, own: true) first, then the published catalog. Templates with several sizes have a separate layout per size; fields are shared by all sizes.

{
  "data": [{
    "id": "tpl_123",
    "name": "Podium Sale",
    "own": false,
    "premium": false,
    "available": true,
    "preview_url": "https://…/preview.png",
    "sizes": [{ "key": "1200x630", "width": 1200, "height": 630 },
              { "key": "1080x1920", "width": 1080, "height": 1920 }],
    "fields": [{ "key": "headline", "label": "Headline", "type": "text" },
               { "key": "photo", "label": "Product photo", "type": "image" }]
  }]
}

POST/projects

Creates a project. sizes picks sizes of the template (default: all). values apply to every banner; each banner's own values override them. Text fields take a string (up to 500 characters); image fields take a public JPEG, PNG, WebP or GIF URL (up to 10 MB, at most 50 per request), which is copied into your storage. Without banners, the design is exported once per size.

curl -X POST https://promorails.com/api/v1/projects \
  -H "Authorization: Bearer pr_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "tpl_123",
    "name": "Black Friday",
    "sizes": ["1200x630", "1080x1920"],
    "values": { "headline": "Black Friday -50%" },
    "banners": [
      { "values": { "photo": "https://example.com/shoes.jpg" } },
      { "values": { "photo": "https://example.com/bag.png", "headline": "Bags -30%" } }
    ],
    "export": true
  }'

Answers 201 with the project (see below).

GET/projects/:id

The project. status: draft, queued, processing, completed or failed. Each banner's outputs maps a size key to its PNG; a project without banners has them in the top-level outputs.

{
  "id": "proj_456",
  "name": "Black Friday",
  "status": "completed",
  "template_id": "tpl_123",
  "sizes": [{ "key": "1200x630", "width": 1200, "height": 630 }, …],
  "fields": [{ "key": "headline", "label": "Headline", "type": "text" }, …],
  "values": { "headline": "Black Friday -50%" },
  "banners": [{
    "id": "ban_1",
    "position": 1,
    "values": { "photo": { "url": "https://…", "width": 1200, "height": 900 } },
    "outputs": { "1200x630": "https://…/1.png", "1080x1920": "https://…/1-1080x1920.png" }
  }],
  "outputs": {},
  "created_at": "2026-11-11T10:00:00.000Z",
  "updated_at": "2026-11-11T10:00:05.000Z"
}

GET/projects

Your projects, newest first, in data. ?limit= 1–100 (default 20).

POST/projects/:id/export

Exports the project again (every banner in every size). Answers 202; poll the project. 409 while an export is running. Each PNG counts as one generation.

DELETE/projects/:id

Deletes the project with its banners, uploaded images and exports. Answers 204.

GET/me

Your plan, its limits, how many projects you have and how much storage your files take (in bytes).

{ "email": "you@example.com", "plan": "pro",
  "limits": { "projects": null, "banners_per_project": 30, "premium_templates": true,
              "watermark": false, "storage_bytes": 2147483648 },
  "usage": { "projects": 4, "storage_bytes": 52428800 } }