--- title: "Important: Two changes to message IDs in the AhaSend API and webhooks" description: "We hate breaking changes too, but to make the APIs more ergonomic and allow for easier integrations and future functionality, we are making each message's ID the same everywhere: in API send responses, in Get Message, in webhooks, in the MCP and in the dashboard. Please check whether they affect your integration.These changes take effect on 9 November 2026." url: https://ahasend.com/blog/important-two-changes-message-ids-ahasend-api-and-webhooks markdown_url: https://ahasend.com/blog/important-two-changes-message-ids-ahasend-api-and-webhooks.md lang: en type: blog_post published: 2026-10-26 updated: 2026-11-04 author: "Mark Kraakman" category: "Product Update" image: https://cms.ahasend.com/sites/default/files/2026-10/message-ids.png --- # Important: Two changes to message IDs in the AhaSend API and webhooks _By Mark Kraakman, October 26, 2026, in Product Update_ ![Two changes to message IDs in the AhaSend API and webhooks](https://cms.ahasend.com/sites/default/files/2026-10/message-ids.png) We hate breaking changes too, but to make the APIs more ergonomic and allow for easier integrations and future functionality, we are making each message's ID the same everywhere: in API send responses, in Get Message, in webhooks, in the MCP and in the dashboard. Please check whether they affect your integration. **These changes take effect on 9 November 2026.** ## 1. The `id` in API send responses The `id` of each recipient in the response of [Create Message](https://ahasend.com/docs/api-reference/messages/create-message), [Create Template Message](https://ahasend.com/docs/api-reference/messages/create-template-message) and [Create Conversation Message](https://ahasend.com/docs/api-reference/messages/create-conversation) becomes a bare UUID. Today it is the full Message-ID header, with angle brackets and a domain. Today: ```javascript { "object": "message", "id": "<0192f5a4-7b1c-7d3e-9a2b-4c5d6e7f8a9b@example.com>", "recipient": { "email": "jane@example.org" }, "status": "queued" } ``` From November 9th: ```javascript { "object": "message", "id": "0192f5a4-7b1c-7d3e-9a2b-4c5d6e7f8a9b", "message_id_header": "<0192f5a4-7b1c-7d3e-9a2b-4c5d6e7f8a9b@example.com>", "recipient": { "email": "jane@example.org" }, "status": "queued" } ``` The Message-ID header moves to a new field, `message_id_header`, in the same response. **What you may need to do** - If you match a send with its webhook events by comparing the response `id` with the webhook's `data.message_id_header`, compare `message_id_header` instead. - If you filter [List Messages](https://ahasend.com/docs/api-reference/messages/get-messages) by `message_id_header` using the `id` from a send response, use `message_id_header` instead. - Don't derive `id` from `message_id_header`, or the other way round: they are not always the same UUID. For example, all copies of one Create Conversation Message send (To, Cc and Bcc) will share one `message_id_header`, while each copy keeps its own `id`. **What keeps working** - [Get Message](https://ahasend.com/docs/api-reference/messages/get-message) and [Cancel Message](https://ahasend.com/docs/api-reference/messages/cancel-message) accept both the new bare `id` and the old `<...@domain>` form. IDs you have already stored keep working. - The Message-ID header of your emails does not change. - If you repeat a request with the same `Idempotency-Key`, you get the stored response of the first request. For up to 24 hours after November 9, a repeat of an earlier request can still return the old form, without `message_id_header`. - Older versions of our SDKs keep working: `id` is still a string. New SDK versions add `message_id_header`. ## 2. The message ID in webhooks and the dashboard [Message webhooks](https://ahasend.com/docs/api-reference/webhooks/message-reception) (`message.reception`, `message.delivered`, `message.transient_error`, `message.failed`, `message.bounced`, `message.suppressed`, `message.opened` and `message.clicked`) carry the message's ID as `data.id`: the same `id` that the send response gave you and that Get Message takes. Today `data.id` is the an internal injection ID, a different UUID written without hyphens. Today: ```javascript "data": { "id": "407926766d2711f09b30960002cafe7c", "message_id_header": "<0192f5a4-7b1c-7d3e-9a2b-4c5d6e7f8a9b@example.com>" } ``` From November 9th: ```javascript "data": { "id": "0192f5a4-7b1c-7d3e-9a2b-4c5d6e7f8a9b", "message_id_header": "<0192f5a4-7b1c-7d3e-9a2b-4c5d6e7f8a9b@example.com>" } ``` **What you may need to do** - If you group a message's webhook events by `data.id`, note that a message sent before November 9 can get events with both IDs: for example a `message.delivered` event with the old ID and a later `message.opened` event with the new one. This can happen for up to 30 days. `data.message_id_header` does not change, so you can group by it across the switch. - If you check the shape of `data.id`, it now has hyphens and is 36 characters long, not 32. - If you archive messages to your own S3 bucket, new archives use the message's ID in their folder and file names. Archives written before November 9 keep their paths. - Campaign messages send the same `message.*` events. Their `data.id` changes to the same 36-character format, with hyphens. Use it to group a campaign message's events. Get Message does not return individual campaign messages (it only works for Transactional messages). - Inbound route webhooks ( `message.routing`) carry the same message ID as `id`, so it matches the `data.id` of that message's `message.reception` event. **What keeps working** - The dashboard shows this same ID as the message's "Message ID". Dashboard links that you already shared keep working. - An ID you stored from an older webhook still works with Get Message and Cancel Message. If you have questions, please reach out via [support@ahasend.com](mailto:support@ahasend.com) or on [our Chat server](https://discord.com/invite/WN4puKFqAA).