← Resources

Developer Reference

Claim Approvals Webhook Reference

UnityTrip notifies your systems as claims move through their lifecycle: for each subscribed event it sends an HTTP request to your endpoint with a JSON payload. This document describes each event type and its payload.

Delivery basics

  • Method: POST
  • Content-Type: application/json
  • Body: a single JSON object per event.
  • Endpoint: the Webhook URL you configure in Ops Manager (the operator console) (Webhooks).
  • A webhook fires only for the event types selected in its configuration.
  • Always respond with a 2xx status code to acknowledge receipt. Any other response, or no response, counts as a failed attempt.

Delivery and security

This reference describes current behaviour and evolves with the platform. When you build a receiver, confirm the specifics with us; we walk every integrator through them.

  • Signature: every delivery carries an X-Webhook-Signature header: an HMAC-SHA256 of the raw request body, keyed with the secret you set for that webhook when you create it in Ops Manager, hex-encoded. Recompute it over the bytes you received, before parsing, and compare in constant time; reject the delivery if it does not match.
  • Retries: up to 10 retries after the first attempt, with exponential backoff starting at one minute (1, 2, 4, 8 minutes and so on, about 17 hours in all). Attempts and their outcomes are visible in Ops Manager.
  • Delivery semantics: an event is sent until it is acknowledged, so the same event can arrive again with a new deliveryId. De-duplicate on the event, not the delivery: its identity is the combination of claimId, eventType and data.timestamp.
  • Source addresses: deliveries do not come from a fixed set of IP addresses. Authenticate by signature rather than by allow-list.

Verification, in outline (Node.js):

const crypto = require("crypto");
function verify(rawBody, header, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return expected.length === header.length &&
         crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

Common envelope

Every event shares this top-level structure; data carries the event-specific fields.

FieldTypeDescription
deliveryIdstring (UUID)Unique ID for this individual delivery attempt. A retry carries a new deliveryId for the same event, so de-duplicate on the event, not on this field (see Delivery and security).
claimIdstring (UUID)Internal unique identifier of the claim.
claimIdentifierstringHuman-readable claim number (e.g. CLM-01533).
eventTypestringThe event name. Determines the shape of data.
timestampstring (ISO 8601)When the event was generated.
dataobjectEvent-specific metadata. See each event below.
costCenterobjectThe cost centre associated with the claim.
costCenter.idstring (UUID)Internal cost centre identifier.
costCenter.namestringDisplay name of the cost centre.
costCenter.identifierstringShort code for the cost centre (e.g. NEIL1).
fundobjectThe fund associated with the claim.
fund.idstring (UUID)Internal fund identifier.
fund.namestringDisplay name of the fund.
requestTitlestringTitle given to the request.
tripReasonstringStated reason for the trip (e.g. Business).
requestDescriptionstringFree-text description of the request.
linkstring (URL)Deep link to the claim in the UnityTrip web app.

Common data fields

These fields appear within data across most event types:

FieldTypeDescription
$typeintegerInternal discriminator identifying the event payload type.
timestampstring (ISO 8601)When the underlying action occurred.
emailstring | nullEmail of the user associated with the action, when applicable. May be null for system-initiated actions.
publishedAtstring (ISO 8601)When the event was published to the delivery queue.
outOfSyncReasonstring | nullReason the claim was flagged out of sync, if any. Empty string or null when none.
approversarray of objectsThe approvers assigned to the claim, in approval order. See The approvers array below.

Event-specific data fields are listed under each event below.


The approvers array

Most events include an approvers array in data: one object per approver in the claim's approval chain, ordered by sequence. It answers who a claim is waiting on without a further API call.

The array is present on ClaimCreatedEvent, ClaimApprovedEvent, ClaimApproverAddedEvent, ClaimUpdatedEvent, ClaimRejectedEvent, ClaimClosedEvent, ClaimRevisionCreated, and ClaimRevisionApprovedEvent. It is not included on ClaimPartialApprovedEvent — see that event for how to advance your pending list.

FieldTypeDescription
approvers[].emailstringEmail address of the approver.
approvers[].namestringDisplay name of the approver (e.g. Mr Neil Test).
approvers[].employeeIdstringThe approver's employee identifier in your organisation.
approvers[].sequenceintegerPosition of this approver in the approval chain, starting at 1. Approvers act in ascending sequence order; a claim is fully approved only once the highest sequence has approved.
approvers[].isSubstitutionbooleantrue if this approver is acting as a delegate or substitute for the originally assigned approver.

Example — a two-approver chain

"approvers": [
  {
    "email": "first.approver@example.com",
    "name": "Mr First Approver",
    "employeeId": "11111",
    "sequence": 1,
    "isSubstitution": false
  },
  {
    "email": "second.approver@example.com",
    "name": "Mr Second Approver",
    "employeeId": "8888",
    "sequence": 2,
    "isSubstitution": true
  }
]
Tip — pending bookings by approver: To surface what each approver still needs to action, track the open claims from ClaimCreatedEvent and ClaimRevisionCreated and group them by approvers[].email (or employeeId). The current approver is the one with the lowest sequence who has not yet approved — show the claim only on their list. When a ClaimPartialApprovedEvent arrives, advance the claim to the next sequence. Remove the claim from all pending lists when you receive a ClaimApprovedEvent (final approval), ClaimRejectedEvent, or ClaimClosedEvent.

ClaimCreatedEvent

Fired when a new claim is created.

Example payload

{
  "deliveryId": "8c7b97c2-6cbe-4ceb-9bee-93cb1fcf8bb9",
  "claimId": "db9adf7d-1522-45ad-ac61-b789a2156267",
  "claimIdentifier": "CLM-01533",
  "eventType": "ClaimCreatedEvent",
  "timestamp": "2026-06-02T01:12:15.9707421+00:00",
  "data": {
    "$type": 7,
    "timestamp": "2026-06-02T01:12:13.9291571+00:00",
    "email": "user@example.com",
    "publishedAt": "2026-06-02T01:12:14.5512303+00:00",
    "approvers": [
      {
        "email": "approver@example.com",
        "name": "Mr Neil Test",
        "employeeId": "11111",
        "sequence": 1,
        "isSubstitution": false
      }
    ]
  },
  "costCenter": {
    "id": "4beda99c-9efd-4b51-ae32-8fcc1b0b48b2",
    "name": "Example Cost Centre",
    "identifier": "NEIL1"
  },
  "fund": {
    "id": "50ba2af9-40f7-41b5-8e10-1a8ba774f746",
    "name": "Training"
  },
  "requestTitle": "Example request",
  "tripReason": "Business",
  "requestDescription": "NEIL1 - Training",
  "link": "https://app.unitytrip.app/claims/db9adf7d-1522-45ad-ac61-b789a2156267"
}

data fields

Uses the common envelope and common data fields. $type is 7.


ClaimApprovedEvent

Fired when a claim is fully approved: the last approver in sequence order has approved. Earlier approvals in a chain fire ClaimPartialApprovedEvent.

Example payload

{
  "deliveryId": "8ab890dc-95d7-47f8-b69d-573ed1831ffb",
  "claimId": "db9adf7d-1522-45ad-ac61-b789a2156267",
  "claimIdentifier": "CLM-01533",
  "eventType": "ClaimApprovedEvent",
  "timestamp": "2026-06-02T01:21:07.3115601+00:00",
  "data": {
    "$type": 1,
    "outOfSyncReason": "",
    "timestamp": "2026-06-02T01:21:05.7020226+00:00",
    "email": "approver@example.com",
    "publishedAt": "2026-06-02T01:21:05.8547919+00:00",
    "approvers": [
      {
        "email": "approver@example.com",
        "name": "Mr Neil Test",
        "employeeId": "11111",
        "sequence": 1,
        "isSubstitution": false
      }
    ]
  },
  "costCenter": {
    "id": "4beda99c-9efd-4b51-ae32-8fcc1b0b48b2",
    "name": "Example Cost Centre",
    "identifier": "NEIL1"
  },
  "fund": {
    "id": "50ba2af9-40f7-41b5-8e10-1a8ba774f746",
    "name": "Training"
  },
  "requestTitle": "Example request",
  "tripReason": "Business",
  "requestDescription": "NEIL1 - Training",
  "link": "https://app.unitytrip.app/claims/db9adf7d-1522-45ad-ac61-b789a2156267"
}

data fields

Uses the common envelope and common data fields. $type is 1.

FieldTypeDescription
outOfSyncReasonstring | nullReason the claim was out of sync, if any, for example when an admin overrides and cancels a claim.

ClaimPartialApprovedEvent

Fired when one approver in a multi-step approval chain approves but the claim still requires approval from one or more later approvers. The claim now advances to the next sequence. A final ClaimApprovedEvent follows once the last approver acts.

Note: Unlike most events, ClaimPartialApprovedEvent does not include the approvers array. Use the chain you captured from ClaimCreatedEvent (or ClaimApproverAddedEvent) to determine who the next approver is. The email field identifies the approver who just acted.

Example payload

{
  "deliveryId": "2e9b40ca-48b2-4c58-89f8-17a47bac21e3",
  "claimId": "b2aa03e8-1fcc-437e-9081-7213b7c52563",
  "claimIdentifier": "CLM-01536",
  "eventType": "ClaimPartialApprovedEvent",
  "timestamp": "2026-06-05T00:55:58.2794482+00:00",
  "data": {
    "$type": 19,
    "outOfSyncReason": "",
    "timestamp": "2026-06-05T00:55:58.1703789+00:00",
    "email": "first.approver@example.com",
    "publishedAt": "2026-06-05T00:55:58.1806732+00:00"
  },
  "costCenter": {
    "id": "d6181b11-ff27-487e-bb40-43e1897a6315",
    "name": "Example Cost Centre (2 approvers)",
    "identifier": "NEIL2"
  },
  "fund": {
    "id": "713a0a07-aac4-4514-9ce0-440e8593448c",
    "name": "Business Meetings"
  },
  "requestTitle": "Example request",
  "tripReason": "Business",
  "requestDescription": "NEIL2 - Business Meetings",
  "link": "https://app.unitytrip.app/claims/b2aa03e8-1fcc-437e-9081-7213b7c52563"
}

data fields

Uses the common envelope and common data fields. $type is 19. The approvers array is not included.

FieldTypeDescription
emailstringEmail of the approver who just approved this step.
outOfSyncReasonstring | nullReason the claim was out of sync, if any, for example when an admin overrides and cancels a claim.

ClaimUpdatedEvent

Fired when an existing claim is updated.

Example payload

{
  "deliveryId": "54d93a54-a99e-411e-9a9c-19849daaf9b2",
  "claimId": "75da7441-5a94-43cf-af42-1f9ee060533c",
  "claimIdentifier": "CLM-01458",
  "eventType": "ClaimUpdatedEvent",
  "timestamp": "2026-06-02T01:24:10.4166107+00:00",
  "data": {
    "$type": 6,
    "reason": "Clarification change made2",
    "timestamp": "2026-06-02T01:24:10.3362989+00:00",
    "email": null,
    "publishedAt": "2026-06-02T01:24:10.3746569+00:00",
    "approvers": [
      {
        "email": "approver@example.com",
        "name": "Mr Neil Test",
        "employeeId": "11111",
        "sequence": 1,
        "isSubstitution": false
      }
    ]
  },
  "costCenter": {
    "id": "1c143e48-3335-4b88-90d3-721ff20f62c5",
    "name": "Example Cost Centre",
    "identifier": "NEIL1"
  },
  "fund": {
    "id": "50ba2af9-40f7-41b5-8e10-1a8ba774f746",
    "name": "Training"
  },
  "requestTitle": "Example request",
  "tripReason": "Business",
  "requestDescription": "NEIL1 - Training",
  "link": "https://app.unitytrip.app/claims/75da7441-5a94-43cf-af42-1f9ee060533c"
}

data fields

Uses the common envelope and common data fields. $type is 6.

FieldTypeDescription
reasonstringReason given for the update.

ClaimRejectedEvent

Fired when a claim is rejected.

Example payload

{
  "deliveryId": "ba4592d2-3c9e-4b60-9bd9-4ffef38159cb",
  "claimId": "7d2e71d0-b8eb-4956-9437-3e4be5c646ff",
  "claimIdentifier": "CLM-01462",
  "eventType": "ClaimRejectedEvent",
  "timestamp": "2026-06-02T01:26:32.5960592+00:00",
  "data": {
    "$type": 2,
    "reason": "",
    "outOfSyncReason": null,
    "timestamp": "2026-06-02T01:26:32.4997626+00:00",
    "email": null,
    "publishedAt": "2026-06-02T01:26:32.5627479+00:00",
    "approvers": [
      {
        "email": "approver@example.com",
        "name": "Mr Neil Test",
        "employeeId": "11111",
        "sequence": 1,
        "isSubstitution": false
      }
    ]
  },
  "costCenter": {
    "id": "1c143e48-3335-4b88-90d3-721ff20f62c5",
    "name": "Example Cost Centre",
    "identifier": "NEIL1"
  },
  "fund": {
    "id": "50ba2af9-40f7-41b5-8e10-1a8ba774f746",
    "name": "Training"
  },
  "requestTitle": "Example request",
  "tripReason": "Business",
  "requestDescription": "NEIL1 - Training",
  "link": "https://app.unitytrip.app/claims/7d2e71d0-b8eb-4956-9437-3e4be5c646ff"
}

data fields

Uses the common envelope and common data fields. $type is 2.

FieldTypeDescription
reasonstringReason given for the rejection. May be an empty string.
outOfSyncReasonstring | nullReason the claim was out of sync, if any, for example when an admin overrides and cancels a claim.

ClaimClosedEvent

Fired when a claim is closed.

Example payload

{
  "deliveryId": "ad84ae04-c2fb-49fb-901c-7f8fecacfada",
  "claimId": "b8fd7e64-5789-42bc-ae5c-087ee3812eb3",
  "claimIdentifier": "CLM-01532",
  "eventType": "ClaimClosedEvent",
  "timestamp": "2026-06-02T01:09:40.879154+00:00",
  "data": {
    "$type": 8,
    "reason": "Closed by admin",
    "byAdmin": true,
    "timestamp": "2026-06-02T01:09:39.777797+00:00",
    "email": null,
    "publishedAt": "2026-06-02T01:09:39.8600662+00:00",
    "approvers": [
      {
        "email": "approver@example.com",
        "name": "Mr Neil Test",
        "employeeId": "11111",
        "sequence": 1,
        "isSubstitution": false
      }
    ]
  },
  "costCenter": {
    "id": "4beda99c-9efd-4b51-ae32-8fcc1b0b48b2",
    "name": "Example Cost Centre",
    "identifier": "NEIL1"
  },
  "fund": {
    "id": "50ba2af9-40f7-41b5-8e10-1a8ba774f746",
    "name": "Training"
  },
  "requestTitle": "Example request",
  "tripReason": "Business",
  "requestDescription": "NEIL1 - Training",
  "link": "https://app.unitytrip.app/claims/b8fd7e64-5789-42bc-ae5c-087ee3812eb3"
}

data fields

Uses the common envelope and common data fields. $type is 8.

FieldTypeDescription
reasonstringReason the claim was closed.
byAdminbooleantrue if the claim was closed by an administrator.

ClaimRevisionCreated

Fired when a revision of a claim is created.

Example payload

{
  "deliveryId": "182967b4-f015-4f0b-b1b9-67fb3c15cef0",
  "claimId": "db9adf7d-1522-45ad-ac61-b789a2156267",
  "claimIdentifier": "CLM-01533",
  "eventType": "ClaimRevisionCreated",
  "timestamp": "2026-06-02T01:26:05.8002028+00:00",
  "data": {
    "$type": 10,
    "reason": "2 days testing of change",
    "version": 1,
    "outOfSyncReason": null,
    "timestamp": "2026-06-02T01:26:05.7511428+00:00",
    "email": null,
    "publishedAt": "2026-06-02T01:26:05.778295+00:00",
    "approvers": [
      {
        "email": "approver@example.com",
        "name": "Mr Neil Test",
        "employeeId": "11111",
        "sequence": 1,
        "isSubstitution": false
      }
    ]
  },
  "costCenter": {
    "id": "4beda99c-9efd-4b51-ae32-8fcc1b0b48b2",
    "name": "Example Cost Centre",
    "identifier": "NEIL1"
  },
  "fund": {
    "id": "50ba2af9-40f7-41b5-8e10-1a8ba774f746",
    "name": "Training"
  },
  "requestTitle": "Example request",
  "tripReason": "Business",
  "requestDescription": "NEIL1 - Training",
  "link": "https://app.unitytrip.app/claims/db9adf7d-1522-45ad-ac61-b789a2156267"
}

data fields

Uses the common envelope and common data fields. $type is 10.

FieldTypeDescription
reasonstringReason given for the revision.
versionintegerVersion number of the revision.
outOfSyncReasonstring | nullReason the claim was out of sync, if any, for example when an admin overrides and cancels a claim.

ClaimRevisionApprovedEvent

Fired when a claim revision is approved.

Example payload

{
  "deliveryId": "c2fd953c-0038-496a-a0ad-4beb36df4a5a",
  "claimId": "db9adf7d-1522-45ad-ac61-b789a2156267",
  "claimIdentifier": "CLM-01533",
  "eventType": "ClaimRevisionApprovedEvent",
  "timestamp": "2026-06-02T01:28:24.2506214+00:00",
  "data": {
    "$type": 14,
    "version": 1,
    "outOfSyncReason": "",
    "timestamp": "2026-06-02T01:28:24.1943104+00:00",
    "email": "approver@example.com",
    "publishedAt": "2026-06-02T01:28:24.2195565+00:00",
    "approvers": [
      {
        "email": "approver@example.com",
        "name": "Mr Neil Test",
        "employeeId": "11111",
        "sequence": 1,
        "isSubstitution": false
      }
    ]
  },
  "costCenter": {
    "id": "4beda99c-9efd-4b51-ae32-8fcc1b0b48b2",
    "name": "Example Cost Centre",
    "identifier": "NEIL1"
  },
  "fund": {
    "id": "50ba2af9-40f7-41b5-8e10-1a8ba774f746",
    "name": "Training"
  },
  "requestTitle": "Example request",
  "tripReason": "Business",
  "requestDescription": "NEIL1 - Training",
  "link": "https://app.unitytrip.app/claims/db9adf7d-1522-45ad-ac61-b789a2156267"
}

data fields

Uses the common envelope and common data fields. $type is 14.

FieldTypeDescription
versionintegerVersion number of the approved revision.
outOfSyncReasonstring | nullReason the claim was out of sync, if any, for example when an admin overrides and cancels a claim.

ClaimApproverAddedEvent

Fired when an approver is added to a claim's approval chain — for example when a substitute or an additional approver is assigned. In addition to the common approvers array, this event's data carries an approver object with the full profile of the person who was added.

Example payload

{
  "deliveryId": "aeacf3d3-e333-4962-96b8-2be2f4f2ee55",
  "claimId": "26c8d4c2-ad48-4ab1-b44f-f556294fcb2b",
  "claimIdentifier": "CLM-01535",
  "eventType": "ClaimApproverAddedEvent",
  "timestamp": "2026-06-05T00:41:33.2669466+00:00",
  "data": {
    "$type": 18,
    "approver": {
      "title": "Mr",
      "firstname": "Second",
      "lastname": "Approver",
      "displayname": "Mr Second Approver",
      "normalizedSearchValue": "mr second approver second.approver@example.com 45454",
      "email": "second.approver@example.com",
      "phone": "45454",
      "employeeId": "8888",
      "employeeLevel": "Grade 3",
      "division": "Operations",
      "department": "Field Services",
      "unit": "Rotations",
      "passengerType": "Staff",
      "subPassengerType": 0,
      "locationId": "100",
      "policyGroupId": "1",
      "id": "6e761b17-9dce-4494-9373-316c779a3469"
    },
    "byAdmin": false,
    "timestamp": "2026-06-05T00:41:33.2103192+00:00",
    "email": "second.approver@example.com",
    "publishedAt": "2026-06-05T00:41:33.2191833+00:00",
    "approvers": [
      {
        "email": "first.approver@example.com",
        "name": "Mr First Approver",
        "employeeId": "11111",
        "sequence": 1,
        "isSubstitution": false
      },
      {
        "email": "second.approver@example.com",
        "name": "Mr Second Approver",
        "employeeId": "8888",
        "sequence": 2,
        "isSubstitution": true
      }
    ]
  },
  "costCenter": {
    "id": "d6181b11-ff27-487e-bb40-43e1897a6315",
    "name": "Example Cost Centre (2 approvers)",
    "identifier": "NEIL2"
  },
  "fund": {
    "id": "713a0a07-aac4-4514-9ce0-440e8593448c",
    "name": "Business Meetings"
  },
  "requestTitle": "Example request",
  "tripReason": "Business",
  "requestDescription": "NEIL2 - Business Meetings",
  "link": "https://app.unitytrip.app/claims/26c8d4c2-ad48-4ab1-b44f-f556294fcb2b"
}

data fields

Uses the common envelope and common data fields. $type is 18.

FieldTypeDescription
byAdminbooleantrue if an administrator added the approver.
approverobjectFull profile of the approver who was added. See below.

The approver object

FieldTypeDescription
idstring (UUID)Internal unique identifier of the approver.
titlestringHonorific title (e.g. Mr).
firstnamestringGiven name.
lastnamestringFamily name.
displaynamestringFull display name.
normalizedSearchValuestringLower-cased, concatenated search string used internally for lookup. Not intended for display.
emailstringEmail address.
phonestringContact phone number.
employeeIdstringEmployee identifier in your organisation.
employeeLevelstringEmployee grade or band (e.g. Grade 3).
divisionstringDivision the approver belongs to.
departmentstringDepartment the approver belongs to.
unitstringOrganisational unit.
passengerTypestringPassenger classification (e.g. Staff).
subPassengerTypeintegerNumeric sub-classification of the passenger type.
locationIdstringIdentifier of the approver's location.
policyGroupIdstringIdentifier of the policy group the approver is assigned to.

Quick reference: event types and $type values

Event type$typeDescription
ClaimCreatedEvent7A new claim is created.
ClaimApprovedEvent1A claim is fully approved (final approval).
ClaimPartialApprovedEvent19One approver in a multi-step chain approves; further approval is still required.
ClaimApproverAddedEvent18An approver is added to the claim's approval chain.
ClaimUpdatedEvent6An existing claim is updated.
ClaimRejectedEvent2A claim is rejected.
ClaimClosedEvent8A claim is closed.
ClaimRevisionCreated10A revision of a claim is created.
ClaimRevisionApprovedEvent14A claim revision is approved.
Note: Always switch on the eventType string rather than the numeric $type discriminator, as $type is an internal value subject to change.

Example payloads above use placeholder emails, names, titles, URLs, identifiers and organisational values. Real payloads will contain your organisation's actual data.

The approvals endpoint these events complement is in the API reference.