Appearance
Templates
Templates are the design of your mail. They are authored in the web app and are read-only over the API — the templates permission has a single action, templates:read.
Why authoring is not programmable
A campaign produces paper. Once printed, nothing can be corrected. A template is therefore created in the web app's editor, where you see exactly what will be printed before you commit to it. Creating, updating and deleting templates are web-app-only operations; an API key calling them receives 403 Forbidden: API keys cannot access this resource.
These endpoints exist so your integration can discover the template ids it needs. See Templates.
List templates
GET
/api/v1/templatesCursor-paginated, newest first. Requires templates:read. Only templates you authored are returned — the internal, immutable content snapshots the platform creates per campaign are never listed.
Query parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
cursor | uuid | — | An id from a previous page |
limit | integer | 20 | 1–100 |
direction | next | prev | next | Page direction |
search | string | — | ≤200 characters. Case-insensitive substring match on the template name |
bash
curl -H "x-api-key: drse_your_api_key" \
"https://api.utskick.dr.se/api/v1/templates?search=summer"ts
const params = new URLSearchParams({ search: "summer" });
const res = await fetch(`https://api.utskick.dr.se/api/v1/templates?${params}`, {
headers: { "x-api-key": process.env.DRSE_API_KEY! },
});
const { data } = await res.json();
const template = data[0];
// `template.id` is what you pass as `templateId` when creating a campaign.200 OK
json
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"name": "Summer postcard",
"kind": "user",
"hasBackPage": true,
"qrCodeUrl": "https://example.com/promo",
"qrCodeDescription": "Landing page",
"qrCodeTrackingEnabled": true,
"createdAt": "2026-07-20T08:00:00.000Z",
"updatedAt": "2026-07-24T16:12:00.000Z"
}
],
"meta": { "count": 3, "nextCursor": null, "prevCursor": null }
}| Field | Notes |
|---|---|
kind | Always user on this endpoint |
hasBackPage | Whether the mail is printed double-sided |
qrCodeUrl | The template's default QR destination, or null. A campaign built from this template inherits it unless you send your own qrCode |
Failures
| Status | code | When |
|---|---|---|
| 400 | validation_failed | Invalid limit, cursor, direction, or search over 200 characters |
| 401 | unauthorized | Key problem |
| 403 | forbidden | Key lacks templates:read |
Retrieve one template
GET
/api/v1/templates/:idRequires templates:read. Returns the template plus short-lived download URLs for its assets.
bash
curl -H "x-api-key: drse_your_api_key" \
https://api.utskick.dr.se/api/v1/templates/550e8400-e29b-41d4-a716-446655440002ts
const id = "550e8400-e29b-41d4-a716-446655440002";
const res = await fetch(`https://api.utskick.dr.se/api/v1/templates/${id}`, {
headers: { "x-api-key": process.env.DRSE_API_KEY! },
});
const { data } = await res.json();
console.log(data.mode, data.hasBackPage, data.images.length);200 OK
json
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"name": "Summer postcard",
"mode": "editor",
"hasBackPage": true,
"frontContentUrl": "https://storage.example/templates/.../content.json?X-Amz-Signature=...",
"backContentUrl": "https://storage.example/templates/.../back-content.json?X-Amz-Signature=...",
"logoUrl": "https://storage.example/templates/.../logo.png?X-Amz-Signature=...",
"returnAddress": "DRSE, Box 1, 111 11 Stockholm",
"returnAddressLogoUrl": null,
"qrCodeUrl": "https://example.com/promo",
"qrCodeDescription": "Landing page",
"qrCodeTrackingEnabled": true,
"images": [
{
"key": "templates/550e8400.../images/018f....png",
"url": "https://storage.example/...?X-Amz-Signature=...",
"page": "front",
"x": 20,
"y": 90,
"w": 60,
"h": 40,
"layer": "above",
"fit": "contain",
"ordinal": 0
}
],
"createdAt": "2026-07-20T08:00:00.000Z",
"updatedAt": "2026-07-24T16:12:00.000Z"
}
}| Field | Notes |
|---|---|
mode | editor for a template designed in the editor, pdf for one backed by an uploaded PDF |
frontContentUrl / backContentUrl | Presigned URLs to the stored design document. backContentUrl is null for single-sided templates |
logoUrl, returnAddressLogoUrl | Presigned image URLs, or null |
returnAddress | The text printed as the sender. A campaign inherits it unless you send your own |
images[] | Placed images. x/y/w/h are millimetres from the top-left of the A4 page; ordinal is draw order; layer is whether the image sits above or below the text |
Asset URLs expire
frontContentUrl, backContentUrl, logoUrl, returnAddressLogoUrl and each images[].url are presigned and short-lived. Use them immediately; do not store or share them. Re-request the template to get fresh URLs.
Failures
| Status | code | When |
|---|---|---|
| 400 | validation_failed | id is not a UUID (Template ID must be a valid UUID) |
| 401 | unauthorized | Key problem |
| 403 | forbidden | Key lacks templates:read |
| 404 | not_found | Template not found — unknown id, a template in another account, or an internal campaign snapshot |
Campaign templateId is not a template you can fetch
The templateId in a campaign response is an internal snapshot of the content at the moment the campaign was created. Fetching it returns Template not found by design. Keep your own record of which authored template you used.