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
| Method | Path | Description |
|---|---|---|
| POST | /api/urls | Queue one or more URLs for processing |
| GET | /api/urls | List all URLs currently in the queue |
| DELETE | /api/urls/:id | Remove URL by id (e.g. cancel before processing) |
| POST | /api/urls/:id/done | Same 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
| Method | POST |
| URL | https://dpbgt.digital365.fi/api/urls |
| Send Body | true |
| Body Content Type | JSON |
| 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:
- 0 s — URL appears in list view at
/. - 0 – 15 min — production VPS poller fetches the queue.
- ~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
- Always:
- Output is written to
output/campaign<N>/<format>/<timestamp>_<note>/on the VPS. - 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.
| Hint | Output | Aliases accepted |
|---|---|---|
#Format-Square | 1080 × 1080 | 1x1, 1:1, feed-square |
#Format-Landscape | 1200 × 628 | 16x9, 1.91:1, feed-landscape |
#Format-Stories | 1080 × 1920 | 9x16, 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
| HTTP | Body | Cause |
|---|---|---|
| 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 |