{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"type":"markdown"},"seo":{"title":"Integration steps","meta":[{"name":"robots","content":"noindex"}],"llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"integration-steps","__idx":0},"children":["Integration steps"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This page explains the end-to-end process of setting up a webhook integration with Spotnana, from initial setup to production deployment."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-1-define-your-requirements","__idx":1},"children":["Step 1: Define your requirements"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before reaching out to Spotnana, identify the following:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The webhook event types that are relevant to your use case (for example, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PNR_V3"]}," for expense management). See ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/openapi/webhookeventapi/webhooks"},"children":["webhook reference"]}," to view the list of events we currently support."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The operations for which you want the events to be triggered. For each event in the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/openapi/webhookeventapi/webhooks"},"children":["webhook reference"]},", see the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["operation"]}," field and its description to learn more about the different event triggers."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your preferred ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/webhooks/webhook-config-model#supported-subscription-models"},"children":["subscription model"]},"."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-2-prepare-your-endpoint","__idx":2},"children":["Step 2: Prepare your endpoint"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set up the HTTPS endpoint that will receive webhook payloads from Spotnana. Your endpoint must:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Accept HTTPS POST requests over TLS 1.2 or higher."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Respond with HTTP 200 OK upon successful receipt."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Implement ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/webhooks/webhook-auth#hmac-signature-verification"},"children":["HMAC-SHA256 signature verification"]}," to authenticate incoming webhook payloads."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["It is also recommended to implement an asynchronous processing queue so your endpoint can accept events immediately and process them in the background."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-3-create-the-webhook-subscription","__idx":3},"children":["Step 3: Create the webhook subscription"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/openapi/webhooksubscriptionapi/webhook-subscription/createwebhooksubscription"},"children":["Create Webhook Subscription"]}," API to create a subscription."," ","To make the API call, you'll need the following information:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Requirement"},"children":["Requirement"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Example"},"children":["Example"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["A name for the subscription"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["name"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["A human-readable identifier for the webhook subscription. It is shown in the Spotnana UI and used for logging purposes. If you don't provide one, Spotnana assigns a default value that you can change later via the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/openapi/webhooksubscriptionapi/webhook-subscription/updatewebhooksubscription"},"children":["update"]}," API."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["spotnana_us"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["spotnana_inc"]},", or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["spotnana"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Event types"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventTypes"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Spotnana uses different webhook event types for the actions occurring on the platform. Review the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/openapi/webhookeventapi/webhooks"},"children":["webhook reference"]}," and let us know which events you want to subscribe to."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TRAVELER_V2"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PNR_V3"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Delivery endpoint"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["url"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The HTTPS URL where Spotnana delivers the webhook payloads. Must use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https"]}," scheme."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://partner.com/api/v1/pnr-update"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Event source"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventSource"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The source companies whose events this subscription receives, set via the optional ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventSource"]}," object (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["COMPANY"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BOOKING_TMC"]},", or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONTRACTING_TMC"]}," predicates). If omitted, it defaults to the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["subscriberId"]}," (i.e., the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["companyId"]}," of the company who owns the subscription). See ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/webhooks/webhook-config-model#supported-subscription-models"},"children":["subscription models"]},"."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CONTRACTING_TMC"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BOOKING_TMC"]}," scope for a TMC-level subscription"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Custom headers"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["customHeaders"]},")"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Any additional static HTTP headers Spotnana should send with each webhook request, as key-value pairs. Optional. Spotnana-managed headers (such as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Authorization"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Content-Type"]},") take precedence over supplied values."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{ \"X-Custom-Header\": \"my-value\" }"]}]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's a sample ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/openapi/webhooksubscriptionapi/webhook-subscription/createwebhooksubscription"},"children":["create webhook subscription"]}," request:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","data-title":"POST /v3/webhooks/subscriptions","header":{"title":"POST /v3/webhooks/subscriptions","controls":{"copy":{}}},"source":"{\n  \"subscriberId\": \"company1-id\",\n  \"name\": \"spotnana_us\",\n  \"url\": \"https://partner.com/api/v1/pnr-update\",\n  \"eventTypes\": [\"PNR_V3\"],\n  \"eventSource\": {\n    \"scopes\": [\n      { \"predicates\": [ { \"type\": \"COMPANY\", \"comparator\": \"IN\", \"values\": [\"company1-id\"] } ] }\n    ]\n  },\n  \"customHeaders\": { \"X-Custom-Header\": \"my-value\" }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["During the setup, you'll be creating this subscription in the sandbox environment. See ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/spotnana/host_urls_doc"},"children":["host URLs documentation"]}," for the sandbox URL."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-4-sandbox-testing-flow","__idx":4},"children":["Step 4: Sandbox testing flow"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Test the webhook delivery in the sandbox environment."," ","To receive the webhook payload, you must implement an endpoint that authenticates and handles incoming ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST"]}," requests using the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/webhooks/webhook-auth"},"children":["HMAC signing secret"]}," returned when the subscription was created."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's an overview of the webhook delivery flow:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Spotnana sends webhook payloads to your delivery endpoint, signed with the HMAC signing secret returned in the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/openapi/webhooksubscriptionapi/webhook-subscription/createwebhooksubscription"},"children":["Create Webhook Subscription"]}," API response (shown only once, at creation)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["A ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST"]}," request is sent to your authenticated endpoint. This request contains the following information:",{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Message Generation Timestamp:"]}," Helps troubleshoot consistency issues with out-of-order deliveries."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Event Type:"]}," Identifies the event that triggered the webhook notification."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Operation:"]}," Describes the specific change that triggered the event (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["FLIGHT_CANCELLED"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BOOKING_CREATED"]},")."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Payload:"]}," Contains the event data."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Audience:"]}," Contains the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["organizationId"]}," needed for a TMC to identify and route the message to the respective organization."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["After receiving the webhook message, your API must send a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["200 OK"]}," response indicating a successful delivery. Any response other than ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["200 OK"]}," will be treated as message delivery failure and will cause the retry mechanism to be initiated."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The sandbox environment mirrors production and uses supplier test environments, so no real bookings or charges are involved."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["During this test, make sure your system:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Handles the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/webhooks/webhook-auth#hmac-signature-verification"},"children":["HMAC authentication protocol"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Receives the event payload and parses the data correctly."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Returns a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["200 OK"]}," response after the webhook message is successfully received."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-5-deploy-to-production","__idx":5},"children":["Step 5: Deploy to production"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Once you've validated that the integration, webhook delivery, and handling are successful through repeated testing in sandbox,"," ","you can create the subscription in the production environment. Follow Step 3 by replacing the sandbox URL with the live production URL."," ","See the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/spotnana/host_urls_doc"},"children":["host URLs documentation"]}," to identify the production URL."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"step-6-monitor-and-maintain","__idx":6},"children":["Step 6: Monitor and maintain"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["After going live, ongoing monitoring is important to keep your integration healthy:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track webhook delivery success rates and set up alerts for elevated failure rates."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Log all incoming events including trace and span IDs for debugging purposes."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Monitor endpoint response times to avoid timeouts."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Periodically check the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/releases/webhookchangelog"},"children":["webhook changelog"]}," to monitor for any new feature releases."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Spotnana has an active monitoring that tracks the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["200 OK"]}," response for every webhook event delivery."]}]},"headings":[{"value":"Integration steps","id":"integration-steps","depth":1},{"value":"Step 1: Define your requirements","id":"step-1-define-your-requirements","depth":2},{"value":"Step 2: Prepare your endpoint","id":"step-2-prepare-your-endpoint","depth":2},{"value":"Step 3: Create the webhook subscription","id":"step-3-create-the-webhook-subscription","depth":2},{"value":"Step 4: Sandbox testing flow","id":"step-4-sandbox-testing-flow","depth":2},{"value":"Step 5: Deploy to production","id":"step-5-deploy-to-production","depth":2},{"value":"Step 6: Monitor and maintain","id":"step-6-monitor-and-maintain","depth":2}],"frontmatter":{"seo":{"title":"Integration steps"}},"lastModified":"2026-06-18T12:59:39.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/webhooks/webhook-integration-steps","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}