Inbox

To integrate Inbox into a non-mobile system, configure a Custom Inbox application and call REST endpoints directly from your backend. This guide walks you through setup, fetching messages, and reporting events.

End-to-end integration for SDK-less surfaces. Your system pulls messages from the public endpoints, renders them in its own UI, and feeds events back through the same endpoints. The SDK paths below wrap these exact endpoints.

For an overview, see the Inbox User Guide.

1. Create a Custom Inbox application

For a system that will integrate without the SDK, first define an application of type Custom Inbox in the panel. Refer to the Inbox Application Guide.

ℹ️

The channel only serves accounts with the Inbox feature (inbox_enabled) switched on. On a disabled account every request is rejected with 400.

2. Fetch messages

Retrieves the user's active messages, newest first. Expired and deleted messages never appear.

GET /api/inbox/getMessages

Messages for identified users are stored by ckey, messages for anonymous users by did. When a request carries both, Dengage reads both mailboxes and merges them — which is why a user who registers later keeps the messages received while anonymous. Custom Inbox requests are authenticated with the app's Public ID.

Query parameters

ParameterRequiredDescription
accYesAccount identifier (account GUID)
didSDK: yesdevice_id — required in SDK integrations
ckeyCustom Inbox: yescontact_key — sent whenever available; mandatory on Custom Inbox
appIdWith ckey: yesApplication GUID — required whenever ckey is sent
limitNoDefault 20 · min 1 · max 100

Response

[
  {
    "smsgId": "ib-8842-15",
    "isRead": false,
    "priority": 1,
    "messageJson": {
      "title": "Siparişiniz kargoda",
      "message": "Siparişiniz yola çıktı, bugün teslim edilecek.",
      "imageUrl": "https://cdn.example.com/inbox/order-shipped.png",
      "type": "imagetext",
      "isPinned": true,
      "receiveDateUTC": "2026-07-10T09:15:00.000Z",
      "ctaButtons": [
        {
          "label": "Siparişi Takip Et",
          "iosDeeplink": "myapp://orders/8842",
          "androidDeeplink": "myapp://orders/8842",
          "webUrl": "https://shop.example.com/orders/8842",
          "buttonId": "1"
        }
      ],
      "messageDetails": "eyJzbXNnSWQiOiJCLTg4NDItMTUiLCJleHAiOjE3..."
    }
  }
]
ℹ️

Keep messageDetails. It is an opaque server token carried by every message. Every event reported for a message must echo it back verbatim, or the backend cannot attribute the interaction. Build events from the message object, not from a bare id.

ℹ️

Empty list ≠ error. If data is temporarily unreachable, the API returns 200 with an empty list instead of an error. Design your UI for this: show an empty state, not a failure state.

3. Display messages — anatomy

Message content arrives as structured data, and your UI renders it however fits your brand — which is also what lets the channel run on screenless surfaces such as IVR.

  1. title — headline of the message
  2. message — main body text
  3. imageUrl — visual content (nullable — present for image and imagetext types)
  4. typetext | image | imagetext
  5. ctaButtons — action buttons (nullable; every field optional): label, iosDeeplink, androidDeeplink, webUrl, buttonId. Prefer the platform deeplink, fall back to webUrl. Echo buttonId on click.
  6. isPinned — pinned messages belong at the top of the list; ordering is your UI's responsibility
  7. priority — set at send time; use it to emphasize important messages
  8. isRead — read state, set by your OP and CL events (IM changes nothing)
  9. receiveDateUTC — when the message reached the Inbox (yyyy-MM-dd'T'HH:mm:ss.SSS'Z')

4. Report events

Reports the user's interactions with messages. The endpoint accepts up to 50 events per request — batch instead of firing one call per event.

POST /api/inbox/events
ℹ️

Batch by design. When the user opens the Inbox and 20 messages are shown, that's 20 Impression events — send them together in one request, not as 20 separate calls.

Event types

CodeEventEffect
IMImpressionStatistics only — the message was visible in the list; changes nothing on the message
OPOpenMarks the message as read
CLClickMarks as read; include the tapped button's buttonId
DTDeleteMarks the message as deleted — it is no longer returned
customCustom eventCustom Inbox apps only — e.g. order approved, coupon used, call completed

The eventType field must be one of these short codes. The SDKs send only the standard codes; on Custom Inbox apps, the custom codes registered for that app are also valid. Events from the SDK and the REST API are stored the same way and feed the same places: reports, analytics, segments, and journey conditions.

Custom event codes

Custom events are defined on the Custom Inbox application (step 1). Each code follows these rules:

  1. Exactly 2 letters (A–Z), automatically converted to uppercase
  2. Cannot be one of the standard codes (IM, OP, CL, DT)
  3. At most 10 active custom events per application
  4. The label can be edited later; the code cannot
⚠️

Events with unregistered codes are rejected by the API — register your codes in the panel before go-live.

⚠️

eventDateUTC rule: always send the current UTC time. Never send a past timestamp or local time. (The SDKs stamp this for you.)

Identifiers

Same rules as fetching: SDK integrations always send did and add ckey when available; an anonymous user's events are processed by did, a contact's events by ckey. Custom Inbox apps send ckey only. appId is required.

Request body

{
  "acc": "90db7e2a-5839-53cd-605f-9d3ffc328e21",
  "ckey": "contact-4471",
  "did": "b7e2f1a0-9c34-4d21-8f6a-2e5b0c7d1a93",
  "appId": "3f9a1c88-2b6e-4a70-9d15-8c4e2f6b0a12",
  "events": [
    {
      "eventType": "CL",
      "msgid": "ib-8842-15",
      "messageDetails": "eyJzbXNnSWQiOiJCLTg4NDItMTUiLCJleHAiOjE3...",
      "eventDateUTC": "2026-07-10T10:22:00Z",
      "buttonId": "1"
    },
    {
      "eventType": "OP",
      "msgid": "ib-8842-15",
      "messageDetails": "eyJzbXNnSWQiOiJCLTg4NDItMTUiLCJleHAiOjE3...",
      "eventDateUTC": "2026-07-10T10:22:00Z"
    },
    {
      "eventType": "IM",
      "msgid": "ib-8811-04",
      "messageDetails": "eyJzbXNnSWQiOiJCLTg4MTEtMDQiLCJleHAiOjE3...",
      "eventDateUTC": "2026-07-10T10:22:00Z"
    }
  ]
}

Response

200 OK
{ }

5. Manage state locally — the hybrid model

Event processing is asynchronous: events pass through a pipeline (collection → processing) and take a short while to fully process. Your UI must not wait for that.

Do: reflect the user's action in the local UI immediately — a deleted message disappears at once; send the event in the background; serve instant experience locally and let the server own durable correctness.

Don't: follow a "send event → wait for processing → refresh" flow — the user would see the result of their own action with a delay.

Error handling

Invalid requests are rejected with 400 and a body of { "message": "..." }.

CaseResult
Invalid limit value400Invalid Value: limit
Unknown account400Invalid Account
Unknown application400Invalid app
Invalid eventType400Invalid Value: eventType
Custom event code not registered for the appRejected — register codes in the panel first
Inbox feature disabled on the account400
Data temporarily unreachable (fetch)200 with an empty list — not an error