dpbgt — banner URLs

REST API

Send banner URLs over HTTP. Each URL is queued, fetched by a poller running every 15 minutes on the production VPS, processed through the banner pipeline (screenshot, MP4, GIF if animated), then removed from the queue.


Endpoints

Base URL: https://dpbgt.digital365.fi

MethodPathDescription
POST/api/urlsQueue one or more URLs for processing
GET/api/urlsList all URLs currently in the queue
DELETE/api/urls/:idRemove URL by id (e.g. cancel before processing)
POST/api/urls/:id/doneSame as DELETE (alias for clients that can't issue DELETE)

Submit a single URL

POST /api/urls

Request body

{
  "url":  "https://www.danpris.net/...#Format-Square#Price-Zooming",
  "note": "Easter campaign"      // optional, free text
}

Response (201 Created)

{ "id": 42 }

Submit multiple URLs

POST /api/urls

Pass an array under urls instead of a single url. The optional note is applied to all of them.

Request body

{
  "urls": [
    "https://www.danpris.net/...#Format-Square",
    "https://www.danpris.net/...#Format-Stories",
    "https://www.danpris.net/...#Format-Landscape"
  ],
  "note": "summer-promo"
}

Response (201 Created)

{
  "ids":     [43, 44, 45],
  "added":   3,
  "skipped": 0,
  "skippedDetails": []   // [{ "url": "...", "reason": "invalid http(s) url" }, ...]
}

List the queue

GET /api/urls

Response (200 OK)

{
  "urls": [
    {
      "id":         42,
      "url":        "https://www.danpris.net/...#Format-Square",
      "note":       "Easter campaign",
      "created_at": 1746431123456
    },
    ...
  ]
}

created_at is a Unix timestamp in milliseconds. The list is sorted newest-first.

Remove a URL from the queue

DELETE /api/urls/:id

Used by the banner-tool poller after a URL has been processed successfully, but you can also call it manually to cancel a queued URL before it's picked up.

Response (200 OK)

{ "removed": 42 }

Code examples

curl
curl -X POST https://dpbgt.digital365.fi/api/urls \
  -H "Content-Type: application/json" \
  -d '{
    "url":  "https://www.danpris.net/...#Format-Square#Price-Zooming",
    "note": "Easter campaign"
  }'
JavaScript / Node.js / browser
async function queueBannerUrl(url, note) {
  const res = await fetch('https://dpbgt.digital365.fi/api/urls', {
    method:  'POST',
    headers: { 'Content-Type': 'application/json' },
    body:    JSON.stringify({ url, note }),
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();   // { id: 42 }
}

await queueBannerUrl(
  'https://www.danpris.net/...#Format-Square#Price-Zooming',
  'Easter campaign',
);
Python (requests)
import requests

r = requests.post(
    'https://dpbgt.digital365.fi/api/urls',
    json={
        'url':  'https://www.danpris.net/...#Format-Square',
        'note': 'Easter campaign',
    },
)
r.raise_for_status()
print(r.json())   # {'id': 42}
PHP (cURL)
$ch = curl_init('https://dpbgt.digital365.fi/api/urls');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS     => json_encode([
        'url'  => $bannerUrl,
        'note' => $note,
    ]),
]);
$response = json_decode(curl_exec($ch), true);
echo $response['id'];  // 42
n8n HTTP Request node
MethodPOST
URLhttps://dpbgt.digital365.fi/api/urls
Send Bodytrue
Body Content TypeJSON
JSON Body{ "url": "{{ $json.banner_url }}", "note": "{{ $json.campaign_name }}" }
Bash one-liner (cron-friendly)
#!/bin/bash
URL="$1"
NOTE="${2:-}"
curl -fsS -X POST https://dpbgt.digital365.fi/api/urls \
  -H "Content-Type: application/json" \
  -d "{\"url\":\"$URL\",\"note\":\"$NOTE\"}"

URL lifecycle

From a successful POST to finished banners on the production VPS:

  1. 0 s — URL appears in list view at /.
  2. 0 – 15 min — production VPS poller fetches the queue.
  3. ~30 s – 5 min per URL — pipeline runs:
    • Always: .png + .jpg (1080×1080 / 1200×628 / 1080×1920 depending on #Format-X)
    • Animated only: .mp4 + .gif
    • Animation is detected from URL hints (Style-Image*, Price-Zooming*) and confirmed at runtime
  4. Output is written to output/campaign<N>/<format>/<timestamp>_<note>/ on the VPS.
  5. Poller calls DELETE /api/urls/:id — URL disappears from the queue.

#Format-X hint

The pipeline picks a Meta ad size from a synthetic hash parameter at the end of the URL. The source page itself ignores the parameter; only the banner tool reads it.

HintOutputAliases accepted
#Format-Square1080 × 10801x1, 1:1, feed-square
#Format-Landscape1200 × 62816x9, 1.91:1, feed-landscape
#Format-Stories1080 × 19209x16, 9:16, reels, story

If no hint is present, the default is square. Make sure the source URL renders natively in the requested aspect — the pipeline does not pad or letterbox, it scales to fit.


Error responses

HTTPBodyCause
400{ "error": "missing url(s)" }No url or urls field provided
400{ "error": "no valid URLs", "skipped": N, "skippedDetails": [...] }All submitted URLs were invalid (must be http or https)
404{ "error": "not found" }DELETE on an id that doesn't exist (already processed or wrong number)
500{ "error": "..." }Server problem — try again, then check the production logs