API reference
Webhooks and events
1.0.0. Dealer and broker accounts.- Mira sends a signed POST to your endpoint for every event on records you created through the API.
- Check the signature on every request, answer within 10 seconds, and ignore repeats by event id.
- Failed deliveries are retried for about two days, and you can resend from the delivery log.
Set up an endpoint
Add an endpoint in Mira Business under Settings, Webhooks: one for live events and, separately, one for test events. It must be HTTPS on port 443 or 8443 and reachable from the public internet. You see its signing secret once, when you add it or replace it.
By default an endpoint receives every event. In settings you can choose only some, by name or by whole group, for example delivery.*; a group also covers events added to it later. The test event is always sent.
What Mira sends
A POST for each event, with the event in the body. Events carry ids and statuses only, never personal details: read the journey or vehicle through the API for more.
POST /your/webhook/path
Mira-Event-Id: 0192f1d0-2a4b-7c3d-8e9f-0a1b2c3d4e5f
Mira-Event-Type: delivery.completed
Mira-Timestamp: 1759140000
Mira-Signature: t=1759140000,v1=<64 hex characters>
{
"id": "0192f1d0-2a4b-7c3d-8e9f-0a1b2c3d4e5f",
"type": "delivery.completed",
"apiVersion": "1.0.0",
"livemode": true,
"createdAt": "2026-10-02T14:03:11Z",
"data": {
"journeyId": "0192f1c2-6f3b-7d2a-9d6e-1a2b3c4d5e6f",
"journeyType": "IDENTITY_DELIVERY",
"journeyStatus": "COMPLETED",
"externalReference": "DMS-88213",
"customerReference": "5f1c7a9e-6f3b-4d2a-9d6e-1a2b3c4d5e6f",
"deliveryStatus": "COMPLETED"
}
}| Header | Meaning |
|---|---|
Mira-Event-Id | The event id. The same event can arrive more than once; use this to ignore repeats. |
Mira-Event-Type | The event type, also in the body. |
Mira-Timestamp | When this delivery was signed, in Unix seconds. |
Mira-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256> |
Verify the signature
v1 is the HMAC-SHA256 of t + "." + raw body, keyed with your endpoint's secret. Compute it over the exact bytes you received, before parsing the JSON, compare in constant time, and reject a t more than 5 minutes old so an old request cannot be replayed.
const crypto = require('crypto')
// rawBody must be the exact bytes received, before any JSON parsing.
function verifyMiraSignature(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
const t = Number(parts.t)
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex')
const given = Buffer.from(parts.v1 || '', 'hex')
return given.length === 32 && crypto.timingSafeEqual(given, Buffer.from(expected, 'hex'))
}Delivery and retries
- Any 2xx within 10 seconds counts as delivered. Redirects are not followed.
- Anything else is retried after 1 minute, 5 minutes, 30 minutes, 2, 6, 12 and 24 hours, then given up on.
- Events can arrive out of order: use
createdAt, or read the record, for the latest state. - If nothing reaches an endpoint for three days, Mira turns it off and emails your company admin. Fix it, save the URL again to turn it back on, and resend what you missed from the delivery log.
Event catalogue
Every event has id, type, apiVersion, livemode, createdAt and data. Journey events carry the journey's ids and statuses; stock events carry your stock code. Events marked simulatable can be forced with a sandbox key.
Journey
| Event | When | Sandbox |
|---|---|---|
journey.created | The journey was accepted. | |
journey.customer_face_replaced | You replaced the customer photo. | |
journey.completed | The handover is complete. Nothing more will happen. | |
journey.cancelled | The journey ended without a handover (cancelled, declined, or the application could not be submitted). | |
journey.expired | The customer did not finish in time. |
Finance
| Event | When | Sandbox |
|---|---|---|
finance_enquiry.submitted | FINANCE_IDENTITY_DELIVERY only: the application is recorded (and, for SUBMIT_VIA_MIRA, being sent to your panel). Finance events are not sent for IDENTITY_DELIVERY, which is approved from the start. | |
finance_enquiry.approved | Finance is approved. | simulatable |
finance_enquiry.declined | Finance is declined. The journey is cancelled. | simulatable |
finance_enquiry.referred | The lender referred the application. It stays pending. | simulatable |
finance_enquiry.submission_failed | SUBMIT_VIA_MIRA only: the application could not be sent to your panel. data.reason is PANEL_NOT_CONFIGURED, PANEL_ERROR or SUBMISSION_ERROR. The journey is cancelled; start a new one to try again. | simulatable |
Identity
| Event | When | Sandbox |
|---|---|---|
identity.requested | The customer has been asked to verify their identity (finance journeys, IDENTITY_DELIVERY and cash-sale DELIVERY). | |
identity.verified | The customer is verified. | simulatable |
identity.under_review | The check needs a person to look at it. | simulatable |
identity.failed | The check failed. The customer can try again. | simulatable |
identity.unavailable | The check could not be started. data.reason is EKYC_NOT_CONFIGURED or PROVIDER_ERROR. The journey stays open and continues once your team resends the check. |
Handover
| Event | When | Sandbox |
|---|---|---|
delivery.created | The handover exists. data.deliveryStatus says what the customer does first. | |
delivery.location_confirmed | The customer confirmed the delivery address (home delivery). | simulatable |
delivery.awaiting_video | The customer can record their handover video. | simulatable |
delivery.video_uploaded | The video arrived and is being checked. | simulatable |
delivery.under_review | The video needs your team to review it. | simulatable |
delivery.completed | The handover was verified. | simulatable |
delivery.cancelled | The handover was cancelled. | simulatable |
delivery.expired | The handover window passed. | simulatable |
Stock
| Event | When | Sandbox |
|---|---|---|
stock.vehicle_sold | A vehicle you sent through the vehicle stock API sold through Mira. data has your stockCode, the vehicleId, soldAt and saleType. |
Other
| Event | When | Sandbox |
|---|---|---|
ping | Sent when you press "Send test event" in settings. |