Skip to main content

Promotions

Posters the menu shows in a pop-up when it opens: create, edit, pause and reorder.

Pop-up posters the menu shows in a modal when it opens, once a day per diner, at most 5.

Every operation comes with its curl and an example response; the keys and ids in the examples are made up. Fields marked with * are required.

List the pop-up promotions

get/restaurants/{ref}/promosrequires menu:readlistPromos

Every promotion in display order, paused ones included. The menu shows the active ones whose dates include now, in a modal when it opens, once a day per diner.

Parameters

NameInDescription
ref*pathThe restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants

Example

curl -X GET "https://delimenu.co/api/v1/restaurants/pizzeria-roma/promos" \
  -H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Response 200

{
  "promos": [
    {
      "id": "8c1f2e4a-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
      "image_url": "https://firebasestorage.googleapis.com/v0/b/example/o/promo-halloween_1080x1080.webp?alt=media",
      "image_width": 864,
      "image_height": 1080,
      "active": true,
      "starts_at": "2026-10-25T05:00:00.000Z",
      "ends_at": "2026-11-01T04:59:59.000Z",
      "link": {
        "type": "url",
        "url": "https://www.instagram.com/pizzeriaroma"
      }
    }
  ]
}

Response fields

FieldTypeDescription
promos*object[]
id*string
image_url*stringThe resized poster (fits 1080×1080, aspect ratio kept)
image_width*number | null
image_height*number | null
active*booleanfalse: paused by the owner
starts_at*string | nullISO 8601. null: no start
ends_at*string | nullISO 8601. null: no end
link*any | nullWhat tapping it does: a "View product" or a "More info" button; null: nothing

Errors

  • 401 UNAUTHORIZED — the key is missing, unknown or revoked
  • 402 NOT_PREMIUM — the restaurant has no active subscription or trial
  • 403 FORBIDDEN — the key lacks the scope this endpoint needs
  • 404 NOT_FOUND — no such restaurant in this account, or no such item in it
  • 500 INTERNAL — something failed on our side; retry in a moment

Create a pop-up promotion

post/restaurants/{ref}/promosrequires menu:writecreatePromo

Downloads the poster at a public https URL (JPG, PNG or WEBP, up to 5 MB) and appends a promotion; takes a few seconds while the image is optimised. Dates are ISO 8601 with offset: the start and the end of the day in the restaurant time zone. At most 5 per restaurant (LIMIT otherwise).

Parameters

NameInDescription
ref*pathThe restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants

Body (JSON)

FieldTypeDescription
image_url*stringPublic https URL of the poster (JPG, PNG or WEBP up to 5 MB). Portrait works best; it is shown whole, never cropped.up to 2048 characters
activebooleanfalse pauses the promo without deleting it. Default true.
starts_atstring | nullWhen it starts showing (ISO 8601 with offset, start of the day). Absent or null: from now.
ends_atstring | nullWhen it stops showing (ISO 8601 with offset, end of the day). Absent or null: no end.
linkany | nullWhat tapping the promo does: { type: "product", product_id } shows a "View product" button, { type: "url", url } a "More info" button. null removes it.

Example

curl -X POST "https://delimenu.co/api/v1/restaurants/pizzeria-roma/promos" \
  -H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"image_url":"https://example.com/fotos/halloween.jpg","starts_at":"2026-10-25T00:00:00-05:00","ends_at":"2026-10-31T23:59:59-05:00","link":{"type":"url","url":"https://www.instagram.com/pizzeriaroma"}}'

Response 201

{
  "promos": [
    {
      "id": "8c1f2e4a-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
      "image_url": "https://firebasestorage.googleapis.com/v0/b/example/o/promo-halloween_1080x1080.webp?alt=media",
      "image_width": 864,
      "image_height": 1080,
      "active": true,
      "starts_at": "2026-10-25T05:00:00.000Z",
      "ends_at": "2026-11-01T04:59:59.000Z",
      "link": {
        "type": "url",
        "url": "https://www.instagram.com/pizzeriaroma"
      }
    }
  ]
}

Response fields

FieldTypeDescription
promos*object[]
id*string
image_url*stringThe resized poster (fits 1080×1080, aspect ratio kept)
image_width*number | null
image_height*number | null
active*booleanfalse: paused by the owner
starts_at*string | nullISO 8601. null: no start
ends_at*string | nullISO 8601. null: no end
link*any | nullWhat tapping it does: a "View product" or a "More info" button; null: nothing

Errors

  • 400 VALIDATION — a field is missing or malformed; `issues` names it
  • 401 UNAUTHORIZED — the key is missing, unknown or revoked
  • 402 NOT_PREMIUM — the restaurant has no active subscription or trial
  • 403 FORBIDDEN — the key lacks the scope this endpoint needs
  • 404 NOT_FOUND — no such restaurant in this account, or no such item in it
  • 500 INTERNAL — something failed on our side; retry in a moment

Update a pop-up promotion

patch/restaurants/{ref}/promos/{id}requires menu:writeupdatePromo

Pause or resume it (active), change its dates or its link, or replace its poster (image_url). Only the fields given change; null removes a date or the link.

Parameters

NameInDescription
ref*pathThe restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants
id*pathThe promotion id, from GET /restaurants/{ref}/promos

Body (JSON)

FieldTypeDescription
image_urlstringA new poster, replacing the current oneup to 2048 characters
activebooleanfalse pauses the promo without deleting it. Default true.
starts_atstring | nullWhen it starts showing (ISO 8601 with offset, start of the day). Absent or null: from now.
ends_atstring | nullWhen it stops showing (ISO 8601 with offset, end of the day). Absent or null: no end.
linkany | nullWhat tapping the promo does: { type: "product", product_id } shows a "View product" button, { type: "url", url } a "More info" button. null removes it.

Example

curl -X PATCH "https://delimenu.co/api/v1/restaurants/pizzeria-roma/promos/8c1f2e4a-5b6d-4e7f-9a0b-1c2d3e4f5a6b" \
  -H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"active":false}'

Response 200

{
  "promos": [
    {
      "id": "8c1f2e4a-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
      "image_url": "https://firebasestorage.googleapis.com/v0/b/example/o/promo-halloween_1080x1080.webp?alt=media",
      "image_width": 864,
      "image_height": 1080,
      "active": false,
      "starts_at": "2026-10-25T05:00:00.000Z",
      "ends_at": "2026-11-01T04:59:59.000Z",
      "link": {
        "type": "url",
        "url": "https://www.instagram.com/pizzeriaroma"
      }
    }
  ]
}

Response fields

FieldTypeDescription
promos*object[]
id*string
image_url*stringThe resized poster (fits 1080×1080, aspect ratio kept)
image_width*number | null
image_height*number | null
active*booleanfalse: paused by the owner
starts_at*string | nullISO 8601. null: no start
ends_at*string | nullISO 8601. null: no end
link*any | nullWhat tapping it does: a "View product" or a "More info" button; null: nothing

Errors

  • 400 VALIDATION — a field is missing or malformed; `issues` names it
  • 401 UNAUTHORIZED — the key is missing, unknown or revoked
  • 402 NOT_PREMIUM — the restaurant has no active subscription or trial
  • 403 FORBIDDEN — the key lacks the scope this endpoint needs
  • 404 NOT_FOUND — no such restaurant in this account, or no such item in it
  • 500 INTERNAL — something failed on our side; retry in a moment

Delete a pop-up promotion

delete/restaurants/{ref}/promos/{id}requires menu:writedeletePromo

Deletes the promotion and its poster. To stop showing it for a while, PATCH active: false instead.

Parameters

NameInDescription
ref*pathThe restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants
id*pathThe promotion id, from GET /restaurants/{ref}/promos

Example

curl -X DELETE "https://delimenu.co/api/v1/restaurants/pizzeria-roma/promos/8c1f2e4a-5b6d-4e7f-9a0b-1c2d3e4f5a6b" \
  -H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Response 200

{
  "promos": []
}

Response fields

FieldTypeDescription
promos*object[]
id*string
image_url*stringThe resized poster (fits 1080×1080, aspect ratio kept)
image_width*number | null
image_height*number | null
active*booleanfalse: paused by the owner
starts_at*string | nullISO 8601. null: no start
ends_at*string | nullISO 8601. null: no end
link*any | nullWhat tapping it does: a "View product" or a "More info" button; null: nothing

Errors

  • 401 UNAUTHORIZED — the key is missing, unknown or revoked
  • 402 NOT_PREMIUM — the restaurant has no active subscription or trial
  • 403 FORBIDDEN — the key lacks the scope this endpoint needs
  • 404 NOT_FOUND — no such restaurant in this account, or no such item in it
  • 500 INTERNAL — something failed on our side; retry in a moment

Reorder the pop-up promotions

put/restaurants/{ref}/promo-orderrequires menu:writereorderPromos

Sets the order the modal shows them in. Pass every promo id exactly once.

Parameters

NameInDescription
ref*pathThe restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants

Body (JSON)

FieldTypeDescription
promo_ids*string[]Every promo id exactly once, in the order the modal shows them

Example

curl -X PUT "https://delimenu.co/api/v1/restaurants/pizzeria-roma/promo-order" \
  -H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"promo_ids":["8c1f2e4a-5b6d-4e7f-9a0b-1c2d3e4f5a6b"]}'

Response 200

{
  "promos": [
    {
      "id": "8c1f2e4a-5b6d-4e7f-9a0b-1c2d3e4f5a6b",
      "image_url": "https://firebasestorage.googleapis.com/v0/b/example/o/promo-halloween_1080x1080.webp?alt=media",
      "image_width": 864,
      "image_height": 1080,
      "active": true,
      "starts_at": "2026-10-25T05:00:00.000Z",
      "ends_at": "2026-11-01T04:59:59.000Z",
      "link": {
        "type": "url",
        "url": "https://www.instagram.com/pizzeriaroma"
      }
    }
  ]
}

Response fields

FieldTypeDescription
promos*object[]
id*string
image_url*stringThe resized poster (fits 1080×1080, aspect ratio kept)
image_width*number | null
image_height*number | null
active*booleanfalse: paused by the owner
starts_at*string | nullISO 8601. null: no start
ends_at*string | nullISO 8601. null: no end
link*any | nullWhat tapping it does: a "View product" or a "More info" button; null: nothing

Errors

  • 400 VALIDATION — a field is missing or malformed; `issues` names it
  • 401 UNAUTHORIZED — the key is missing, unknown or revoked
  • 402 NOT_PREMIUM — the restaurant has no active subscription or trial
  • 403 FORBIDDEN — the key lacks the scope this endpoint needs
  • 404 NOT_FOUND — no such restaurant in this account, or no such item in it
  • 500 INTERNAL — something failed on our side; retry in a moment

Developers