Download OpenAPI specification:
API documentation for mein-plakat
Creates a new permission (scope) on a resource server.
| resourceServerId required | string The ID of the resource server (API) |
| value required | string The permission scope value (e.g., read:users) |
| description | string |
{- "resourceServerId": "string",
- "value": "string",
- "description": "string"
}Deletes a permission (scope) from a resource server.
| resourceServerId required | string |
| value required | string |
{- "resourceServerId": "string",
- "value": "string"
}Adds a location to the user's watchlist.
| providerId required | string |
| locationId required | string |
| positionNumber | number Position number (default 1) |
{- "providerId": "string",
- "locationId": "string",
- "positionNumber": 0
}Updates the profile of the currently logged-in user.
| name | string |
| nickname | string |
| firstName | string |
| lastName | string |
| phone | string |
| companyName | string |
{- "name": "string",
- "nickname": "string",
- "firstName": "string",
- "lastName": "string",
- "phone": "string",
- "companyName": "string"
}Creates a ticket in the Simple Support System (project mein_plakat).
| title required | string |
| content required | string |
| ticketPriority required | string Enum: "trivial" "minor" "major" "critical" "blocker" |
Array of objects |
{- "title": "string",
- "content": "string",
- "ticketPriority": "trivial",
- "attachments": [
- {
- "filename": "string",
- "mimeType": "string",
- "contentBase64": "string"
}
]
}Imports SDAW records from a file (text content).
SDAW file content
{- "success": true,
- "messageType": "string",
- "baseId": "string",
- "stats": { }
}Extracts column headers from uploaded schedule file for mapping. Admin permission required.
| file required | string <base64> Base64 encoded Excel or CSV file |
{- "file": "string"
}{- "valid": true,
- "columns": [
- {
- "key": "string",
- "name": "string"
}
], - "defaultMapping": { }
}Imports schedule (Terminplan) data from Excel/CSV with field mapping. Replaces only business years present in file. Admin permission required.
| file required | string <base64> Base64 encoded Excel or CSV file |
| mapping required | object Column index to field name mapping (e.g. 0 to year, 1 to period) |
{- "file": "string",
- "mapping": { }
}{- "success": true,
- "count": 0
}Generates a temporary CloudFront signed URL for a private file (admin only).
| key required | string File key to request. |
| download | boolean When true the URL is signed against S3 with Content-Disposition attachment, so the browser saves the file instead of displaying it. |
| fileName | string Name the saved file gets; only used together with download. |
{- "key": "550e8400-e29b-41d4-a716-446655440000.pdf",
- "download": true,
- "fileName": "motiv.pdf"
}{
}Extracts column headers from uploaded Excel file for mapping (admin only).
| file required | string <base64> Base64 encoded Excel file (xls or xlsx) |
{- "file": "string"
}{- "valid": true,
- "columns": [
- {
- "key": "string",
- "name": "string"
}
]
}Imports municipality directory data from Excel file with field mapping (admin only).
| file required | string <base64> Base64 encoded Excel file |
| mapping required | object Mapping of original column keys to target field names |
{- "file": "string",
- "mapping": { }
}{- "success": true,
- "count": 0
}Returns paginated list of locations missing data for a given coverage metric. Admin permission required.
| metric required | string Enum: "locationPhotos" "consumerMarketPhotos" "consumerMarketAddresses" "municipalityDirectory" "availableSpaces" "performanceValues" "mailingAddresses" "schedulesDecadicABlock" "schedulesDecadicBBlock" "schedulesDecadicCBlock" "schedulesWeekly" "schedules14day" "schedulesMonthly" "schedulesQuarterly" "schedulesHalfYearly" "schedulesYearly" |
| businessYear | integer |
| page | integer Default: 1 |
| limit | integer <= 100 Default: 25 |
| sortBy | string |
| sortOrder | string Enum: "ASC" "DESC" |
| search | string |
{- "items": [ ],
- "pageInfo": {
- "total": 0,
- "page": 0,
- "limit": 0,
- "totalPages": 0,
- "hasNextPage": true,
- "hasPreviousPage": true
}
}Execute GraphQL queries and mutations against the mein-plakat API.
Available Queries:
checkPermissions - Check if current user has admin permissionslocationPhotos(page, limit, districtId, providerId) - Get location photos with paginationlocationPhoto(id) - Get a single location photo by IDconsumerMarketPhotos(page, limit, consumerMarketId, providerId) - Get consumer market photos with paginationconsumerMarketPhoto(id) - Get a single consumer market photo by IDlogs(page, limit, app, level) - Get logs with paginationsdawBaseRecords(type, page, limit) - Get SDAW base records (filtered by type)sdawBaseRecord(id, type) - Get a single SDAW base recordsdawDetailRecords(baseId, type, collectionSuffix, page, limit) - Get SDAW detail metadata (actual data from S3 via REST)importStats - Get overall import statisticsusers(page, limit, sortBy, sortOrder) - Get users with paginationreceivedEmails(page, limit, sortBy, sortOrder) - Get received emails with paginationsentEmails(page, limit, sortBy, sortOrder) - Get sent emails with paginationcombinedAdvertisingMedia(...) - Werbeträger merged locations (filterChain, counterSnapshots, optional extended PpS metrics)advertisingMediaFilterContext(...) - Candidate row count; optional PpS bounds and population min/max (prefix chain, scan-capped)geoRadiusMunicipalityPreview(addressLine, radiusKm) - Geocode center + municipalities with location counts inside radius (Nominatim + scan)Example Query:
query {
locationPhotos(page: 1, limit: 10) {
items {
_id
districtId
providerId
originalPath
variants { size type path }
}
pageInfo { total hasNextPage }
}
}
| query required | string GraphQL query string |
| variables | object Optional variables for the query |
| operationName | string Optional operation name if query contains multiple operations |
{- "query": "query { locationPhotos(limit: 5) { items { _id districtId } } }",
- "variables": { },
- "operationName": "string"
}{- "data": { },
- "errors": [
- {
- "message": "string",
- "locations": [ ],
- "path": [ ]
}
]
}Hands back everything the browser needs to put a file into the private files bucket by itself (admin only). Up to 64 MB that is one signed PUT; above it the answer carries the part URLs of a multipart upload instead, so gigabyte print data survives a broken line. Report the result to /v1/uploads/complete afterwards, that is where size and checksum are read off the stored object.
| scope required | string Enum: "motifs" "articles" Where the file belongs. |
| referenceId | string Id of the record the file hangs on, used as a folder. |
| filename required | string |
| contentType | string |
| size | integer Size of the file in bytes. Decides single PUT or multipart. |
{- "scope": "motifs",
- "referenceId": "507f1f77bcf86cd799439011",
- "filename": "motiv-v2.pdf",
- "contentType": "application/pdf",
- "size": 1073741824
}{- "mode": "single",
- "key": "motifs/507f1f77bcf86cd799439011/9f1c-motiv-v2.pdf",
- "uploadUrl": "string",
- "uploadId": "string",
- "partSize": 0,
- "parts": [
- {
- "partNumber": 0,
- "url": "string"
}
], - "contentType": "string",
- "expiresIn": 0,
- "maxBytes": 0
}Closes a multipart upload when parts were used and then reads size, content type and checksum off the stored object (admin only). Nothing here is taken from the caller: a file over the limit of its scope or of a type the scope does not accept is deleted again right away, because at that point it already lies in the bucket.
| scope required | string Enum: "motifs" "articles" |
| key required | string The key from the presign call. |
| filename | string |
| uploadId | string Only for a multipart upload. |
Array of objects Only for a multipart upload, the ETag of every part. |
{- "scope": "motifs",
- "key": "motifs/507f1f77bcf86cd799439011/9f1c-motiv-v2.pdf",
- "filename": "string",
- "uploadId": "string",
- "parts": [
- {
- "partNumber": 0,
- "etag": "string"
}
]
}{- "key": "string",
- "filename": "string",
- "contentType": "string",
- "size": 0,
- "checksum": "string"
}Removes the parts of an unfinished multipart upload (admin only). Until it is completed no object exists under the key at all, so an upload that breaks off leaves no half file behind; this only makes sure the orphaned parts are not billed until the bucket rule clears them.
| scope required | string Enum: "motifs" "articles" |
| key required | string |
| uploadId required | string |
{- "scope": "motifs",
- "key": "string",
- "uploadId": "string"
}Creates an async export job. Returns immediately with jobId. SIS process-exports task picks up pending jobs and generates the file. Admin permission required.
| format required | string Enum: "csv" "xlsx" |
required | object |
{- "format": "csv",
- "view": {
- "queryName": "string",
- "lang": "de"
}
}{- "jobId": "string",
- "message": "string"
}Returns paginated documents from a collection. Supports search. Admin permission required.
| name required | string Collection name |
| page | integer Default: 1 |
| limit | integer <= 100 Default: 50 |
| search | string Search in common fields (min 2 chars) |
{- "data": {
- "items": [ ],
- "total": 0,
- "page": 0,
- "limit": 0
}
}Returns AWS Cost Explorer data (current month costs, estimated month-end, past 12 months). Cached for 1 hour. Admin permission required.
{- "data": {
- "currentMonthCost": 0,
- "estimatedMonthEndCost": 0,
- "currency": "USD",
- "pastMonths": [
- {
- "month": "2025-02",
- "label": "Feb. 25",
- "cost": 0
}
]
}, - "cached": true
}Returns filter options for objectTypes and illuminations. No authentication required. Used by the Site app for dynamic filter loading.
{- "objectTypes": [
- {
- "id": "507f1f77bcf86cd799439011",
- "title": "Litfaßsäule",
- "language": "de",
- "mainPositionType": "LFS",
- "subPositionType": null
}
], - "illuminations": [
- {
- "id": "507f1f77bcf86cd799439011",
- "code": "H",
- "language": "de",
- "title": "Hinterleuchtung"
}
]
}Returns the closest MunicipalityDirectory entries to the given lat/lng (deduped by AGS). With useIp=1 and no lat/lng, resolves approximate coordinates from the caller IP: optional local GeoIP2-compatible local City MMDB e.g. DB-IP Lite (GEOIP_CITY_MMDB_PATH), then HTTPS ipwho.is. Loopback IPs use GEOIP_DEV_FALLBACK_* if set.
| lat | number |
| lng | number |
| limit | integer Default: 3 |
| useIp | string If 1 and lat/lng omitted, use client IP for coarse geolocation |
Returns a GeoJSON FeatureCollection of municipality (8-digit AGS) and/or Kreis (5-digit)
outlines for the requested codes. Unknown codes are skipped. No authentication required.
| codes required | string Example: codes=05315000,05334 Comma-separated municipality (8-digit AGS) or Kreis (5-digit) codes |
Returns detailed information for an advertising location identified by its slug. Includes free booking terms (only periods whose end date is on or after today, Europe/Berlin), image variants, and core location data.
| slug required | string Example: 3910841-b169-auer-str-69a-li URL-safe slug (providerId+locationNumber+positionNumber+locationDescription) |
{- "slug": "3910841-b169-auer-str-69a-li",
- "locationDescription": "string",
- "postalCode": "string",
- "district": "string",
- "pricePerDay": 0,
- "positionType": "string",
- "lighting": "string",
- "constructionType": "string",
- "constructionTypeDisplayValue": "string",
- "durationType": "string",
- "durationTypeDisplayValue": "string",
- "positionNumberTo": 0,
- "latitude": 0,
- "longitude": 0,
- "qid": 0,
- "photoName": "string",
- "dimensionsHeight": 0,
- "dimensionsWidth": 0,
- "fawTags": [
- {
- "tag": "string",
- "label": "string"
}
], - "consumerMarket": {
- "chain": "string",
- "number": "string",
- "squareMeters": 0,
- "statisticalLocationCode": "string",
- "statisticalLocationInfo": {
- "municipalityName": "string",
- "populationTotal": 0,
- "postalCode": "string",
- "latitude": 0,
- "longitude": 0
}, - "street": "string"
}, - "freeTerms": [
- {
- "freePeriod": 0,
- "dateFrom": "2019-08-24T14:15:22Z",
- "dateTo": "2019-08-24T14:15:22Z",
- "pricePerDay": 0,
- "calculatedDays": 0,
- "businessYear": 0
}
], - "ppsLwt": 0,
- "lwtPerformanceValues": [
- {
- "performanceValue": 0,
- "performanceSource": "string",
- "validityFrom": "2019-08-24T14:15:22Z",
- "validityTo": "2019-08-24T14:15:22Z"
}
], - "image": {
- "originalPath": "string",
- "originalWidth": 0,
- "originalHeight": 0,
- "originalSize": 0,
- "uuid": "string",
- "variants": [
- {
- "size": "string",
- "type": "string",
- "url": "string",
- "width": 0,
- "height": 0,
- "fileSize": 0
}
]
}, - "consumerMarketPhoto": { }
}Alternative to slug lookup. Returns the same location details (free terms, image info) when identified by providerId, locationNumber, and positionNumber. IDs are parsed as integers.
| providerId required | string Example: 39 Sender identification (integer) |
| locationId required | string Example: 10841 Location number |
| positionId required | string Example: 1 Position number |
Returns all attachments for a given email template (admin only).
| templateId required | string Example: 507f1f77bcf86cd799439011 The email template ID. |
{- "attachments": [
- {
- "id": "507f1f77bcf86cd799439012",
- "filename": "document.pdf",
- "s3Key": "email-templates/507f1f77bcf86cd799439011/abc123.pdf",
- "contentType": "application/pdf",
- "size": 12345,
- "uploadedAt": "2025-01-01T00:00:00.000Z"
}
]
}Uploads a file attachment for an email template. The file is stored in S3 and metadata is saved in the template document (admin only).
| templateId required | string Example: 507f1f77bcf86cd799439011 The email template ID. |
| file required | string Base64-encoded file content. |
| filename required | string Original filename. |
| contentType | string MIME type of the file. |
{- "file": "JVBERi0xLjQK...",
- "filename": "document.pdf",
- "contentType": "application/pdf"
}{- "attachment": {
- "id": "string",
- "filename": "string",
- "s3Key": "string",
- "contentType": "string",
- "size": 0,
- "uploadedAt": "2019-08-24T14:15:22Z"
}
}Deletes a file attachment from an email template. Removes the file from S3 and the metadata from the template document (admin only).
| templateId required | string Example: 507f1f77bcf86cd799439011 The email template ID. |
| attachmentId required | string Example: 507f1f77bcf86cd799439012 The attachment ID. |
{- "success": true
}Resolves the token of an approval mail to the whole changed order, not just to the list of changes: positions, sales articles, what changed and the price effect. The token only names the request; the login decides who may see it, so a stranger with the link gets nothing.
| token required | string |
The motif behind the upload link of the customer interaction (5.4.2), with the request that was sent and whether the link is still open. It closes as soon as a newer version arrived in the meantime, otherwise the customer would overwrite the newer state.
| id required | string |
Behind the login, never on an open token (your ruling of 13.08.2026). The link closes as soon as a newer version arrived in the meantime. The same file again is not a new version: the checksum of the stored object decides that, the same rule as in the admin (5.4.2).
| id required | string |
| key required | string the key from the presign call |
| filename required | string |
| uploadId | string only for a multipart upload |
Array of objects only for a multipart upload, the ETag of every part |
{- "key": "string",
- "filename": "string",
- "uploadId": "string",
- "parts": [
- {
- "partNumber": 0,
- "etag": "string"
}
]
}Print data for posters runs into gigabytes and never goes through the Lambda: the browser gets a signed URL and puts the file into the bucket itself. The link is checked here as well, so a closed one hands out no URL in the first place.
| id required | string |
| filename required | string |
| contentType | string |
{- "filename": "string",
- "contentType": "string"
}Resolves the cart to poster formats over the assignment table, builds the offer of sales articles per format out of the article master (checkout role, display condition, option groups) and prices it with the dated price rows of the customer group. Also returns the open projects the order may be attached to, the invoice addresses and the print files already staged.
Writes the order, its booked positions, the motifs the choice implies and the sales articles that hang on no motif, then authorizes the payment. Nothing is charged and no mail goes out. A booking spanning two business years is split right here.
| paymentMethod required | string Enum: "invoice" "bank_transfer" "direct_debit" |
| projectId | string An open project of this customer, optional |
| invoiceAddressId | string |
| note | string |
| selection | object What the customer chose, keyed by poster format id |
{- "paymentMethod": "invoice",
- "projectId": "string",
- "invoiceAddressId": "string",
- "note": "string",
- "selection": { }
}Print data for posters runs from hundreds of megabytes into gigabytes, so it never goes through the Lambda: the browser gets a signed URL, puts the file into the bucket itself and hands back only the key. The content type is part of the signature.
| filename required | string |
| contentType | string |
{- "filename": "string",
- "contentType": "string"
}A motif hangs on a project and may never move between projects, so a file the customer brings in the checkout is parked until it can be assigned. Size and checksum are read off the stored object, not off what the caller claims.
| key required | string the key from the presign call |
| filename required | string |
| posterFormatId | string |
| title | string |
| uploadId | string only for a multipart upload |
Array of objects only for a multipart upload, the ETag of every part |
{- "key": "string",
- "filename": "string",
- "posterFormatId": "string",
- "title": "string",
- "uploadId": "string",
- "parts": [
- {
- "partNumber": 0,
- "etag": "string"
}
]
}Returns the current user's cart lines with optional term alternatives per line. Enriched with municipalityNameSnapshot, districtSnapshot, and thumbnailUrl (location photo) when available.
{- "items": [
- { }
]
}Adds a bookable term as a cart line. Duplicate provider/location/position/termin returns 409.
| providerId required | string |
| locationId required | string |
| positionNumber | string Optional; defaults from location when omitted |
| terminId required | string Encoded term identifier (business year + free period) |
| slug | string Optional SEO slug snapshot (max 256 chars) |
{- "providerId": "string",
- "locationId": "string",
- "positionNumber": "string",
- "terminId": "string",
- "slug": "string"
}Switches the bookable term for an existing line; pricing and dates are recalculated from free terms.
| itemId required | string |
| terminId required | string |
{- "terminId": "string"
}Synchronizes Auth0 user data to the local database after login. Called from frontend after successful authentication.
| auth0Id | string |
string | |
| firstName | string |
| lastName | string |
{- "auth0Id": "string",
- "email": "string",
- "firstName": "string",
- "lastName": "string"
}Updates a user in Auth0 and local database. Admin permission required.
| id required | string |
| auth0Data | object Data to update in Auth0 (name, nickname, blocked, etc.) |
| localData | object Data to update in local database |
| roles | Array of strings Array of role IDs to assign |
{- "auth0Data": { },
- "localData": { },
- "roles": [
- "string"
]
}Updates a role in Auth0, including name, description, and assigned permissions.
| id required | string |
| name | string |
| description | string |
Array of objects |
{- "name": "string",
- "description": "string",
- "permissions": [
- {
- "permission_name": "string",
- "resource_server_identifier": "string"
}
]
}Criteria in plain words (places, categories, period, budget, environment, products to
advertise) to the site's filter state, then a Typesense search. Answers with a German
summary in result (count, split by category and lighting, the first hits with price and
identifier) and the filterState the site applies to its search page. No authentication.
| locations | Array of strings |
| radiusKm | number Die Seite bietet 5, 10, 20, 30 und 50 km; andere Werte werden aufgerundet, mehr als 50 wird 50. |
| categories | Array of strings Items Enum: "largeFormat" "cityLightPoster" "advertisingColumns" "digitalScreens" |
| positionTypes | Array of strings |
| illuminated | boolean |
| lighting | Array of strings Items Enum: "B" "H" "U" B beleuchtet, H hinterleuchtet, U unbeleuchtet; hat Vorrang vor illuminated. |
| environment | Array of strings |
| advertisedProducts | Array of strings |
| durationTypes | Array of strings Items Enum: "weekly" "decade" |
| dateFrom | string <date> |
| dateTo | string <date> |
| minPricePerDay | number |
| maxPricePerDay | number |
| text | string |
| sort | string Enum: "price_asc" "price_desc" "relevance" |
| limit | integer [ 0 .. 10 ] 0 returns count, split and filterState only |
{- "locations": [
- "Köln"
], - "radiusKm": 20,
- "categories": [
- "largeFormat"
], - "positionTypes": [
- "GF"
], - "illuminated": true,
- "lighting": [
- "B"
], - "environment": [
- "Bahnhof"
], - "advertisedProducts": [
- "Bier"
], - "durationTypes": [
- "weekly"
], - "dateFrom": "2019-08-24",
- "dateTo": "2019-08-24",
- "minPricePerDay": 0,
- "maxPricePerDay": 0,
- "text": "string",
- "sort": "price_asc",
- "limit": 10
}{- "ok": true,
- "result": "string",
- "found": 0,
- "places": [
- "string"
], - "filterState": { },
- "searchQuery": "string"
}Type, size, lighting, price per day, environment, advertising bans and the free booking periods (weeks or decades) of one space, optionally only those overlapping a period. No authentication.
| space required | string Identifier from the search, a details link or providerId_locationNumber_positionNumber |
| dateFrom | string <date> |
| dateTo | string <date> |
{- "space": "string",
- "dateFrom": "2019-08-24",
- "dateTo": "2019-08-24"
}Validates the request and mails it to the mein-plakat mailbox (reply-to the customer).
Only the fonella tools may call it: they send the key in X-Assistant-Key. Missing or
invalid fields come back with ok false and the reasons in result.
| X-Assistant-Key required | string |
| name required | string |
| company | string |
string <email> | |
| phone | string |
| message required | string |
| locations | Array of strings |
| categories | Array of strings |
| spaces | Array of strings |
| dateFrom | string <date> |
| dateTo | string <date> |
| period | string |
| budget | string |
| confirmed required | boolean The customer confirmed sending the request |
{- "name": "string",
- "company": "string",
- "email": "user@example.com",
- "phone": "string",
- "message": "string",
- "locations": [
- "string"
], - "categories": [
- "string"
], - "spaces": [
- "string"
], - "dateFrom": "2019-08-24",
- "dateTo": "2019-08-24",
- "period": "string",
- "budget": "string",
- "confirmed": true
}The form on the website sends here. No key: the request must come from a page of the site
(Origin header), the hidden field website must stay empty and startedAt (epoch
milliseconds when the form was opened) must be at least three seconds old. Same fields and
checks as the assistant's offer request; confirmed is the checkbox of the form. Mails to
the mein-plakat mailbox with the customer's address as reply-to.
| name required | string |
| company | string |
string <email> | |
| phone | string |
| message required | string |
| locations | Array of strings |
| categories | Array of strings |
| spaces | Array of strings |
| dateFrom | string <date> |
| dateTo | string <date> |
| period | string |
| budget | string |
| confirmed required | boolean |
| startedAt required | integer Epoch milliseconds when the form was opened |
| website | string Trap field, must stay empty |
| pageUrl | string |
| language | string |
{- "name": "string",
- "company": "string",
- "email": "user@example.com",
- "phone": "string",
- "message": "string",
- "locations": [
- "string"
], - "categories": [
- "string"
], - "spaces": [
- "string"
], - "dateFrom": "2019-08-24",
- "dateTo": "2019-08-24",
- "period": "string",
- "budget": "string",
- "confirmed": true,
- "startedAt": 0,
- "website": "string",
- "pageUrl": "string",
- "language": "string"
}