Back to blog
Adal Cloud journal

CI/CD and ephemeral environments: how to receive webhooks in preview environments

Deployments come and go. Webhooks need a stable entry point and a route to the right branch.

Published on
CI/CD and ephemeral environments: how to receive webhooks in preview environments

A developer opens a pull request. CI builds the application, deploys an isolated environment, and posts a preview link. The team can review the interface, try the signup flow, and share the changes with colleagues.

Then QA tests an external integration. A test payment succeeds, but the order still shows as unpaid: the provider's webhook URL points to shared staging. Or the URL is correct, but the event arrives during a redeploy, before the handler is ready.

Temporary environments have their own lifecycle. They are created for a task, rebuilt as the code changes, and removed when testing is done. The external service knows nothing about the pull request. It sends events to its registered URL on its own schedule.

Testing these integrations before a merge means making webhook delivery part of the preview environment. Adal Cloud separates the public entry point from the application that processes the event: the provider sends its request to a Server's URL, and a Destination defines where that request goes next.

An application preview needs its integrations too

Ephemeral environments are temporary deployments created for a branch, pull request, or test run. A branch preview lets the team review a change in isolation. A temporary deployment can help reproduce a bug. A QA environment gives testers a separate set of data for release checks.

For webhook testing, the external event also needs to reach the specific instance of the application under review.

Consider two branches being tested at the same time. One changes subscription handling; the other changes refunds. If both use the same provider test account and webhook URL, events may end up in shared staging or reach both previews. The tests start interfering with each other: one creates data, and the other receives an event it never expected.

A useful test connects four things: the branch, its test data, the event source, and the handler. A preview URL gives you an address for the application. The rest of that connection still needs to be configured.

Use test credentials and isolated data for these checks. A preview running an experimental handler should not receive production events, initiate real payments, or send notifications to customers.

A stable entry point for a temporary application

The URL of a Server in Adal Cloud remains valid for as long as the Server exists. Register it with the provider and keep it when you rebuild the application. The delivery address in the Destination can change while the public entry point stays the same.

For a single test flow, the route looks like this:

Provider's test environment → stable HTTPS URL of a Server in Adal Cloud → Request → Destination for the current preview → handler running the branch under review

Suppose the preview for PR-184 gets a new address after a redeploy. If the team keeps the same Server for that PR, the provider's webhook URL can stay as it is. Update the Destination's address and verify delivery to the new application instance.

The application and its webhook entry point now have separate lifecycles. You can rebuild the application more often than you replace the public endpoint. With persistent storage enabled, captured requests and their history remain available within the retention period, even after the temporary application has stopped.

Delivering to public and private previews

If the preview's webhook handler is reachable from the internet, use a Direct HTTP Destination. Adal Cloud forwards the accepted request to the application's public address.

For an environment inside a private network, run Adal CLI where it can reach the application:

External service → Server in Adal Cloud → Adal CLI inside the preview's network → internal webhook handler

Adal CLI establishes a secure outbound connection. The internal handler does not need a public IP address or an open inbound port. The Destination URL must be reachable from the machine or container running the CLI. In particular, localhost inside one container does not refer to an application in another container.

Keep the CLI running for as long as the preview is in use. Starting it inside a short CI job means the connection ends with that job, even if QA still needs the environment. The delivery process belongs in the deployment's lifecycle.

The handler must still verify the provider's signature and validate the request before performing any actions.

Preview access controls also affect the route. A page that opens in a browser after login may be inaccessible to a server sending an HTTP request. Direct HTTP needs a reachable handler, so check how incoming delivery will be authorized. The Destination documentation covers both delivery methods.

Keeping parallel branches separate

A stable webhook URL does not determine which PR an event belongs to. Choose the setup based on the checks your team needs to run concurrently.

Testing setup Webhook configuration What to account for
One QA environment used for sequential checks A persistent Server with a Destination pointing to the current deployment Finish the current test and account for pending events before switching deployments
Several independent branch previews A separate Server and test event flow for each preview The provider must support separating events through endpoints or test accounts
Comparing two versions of a handler One Server with two Destinations, delivering the same request to both versions Delivery to both is intentional; isolate their data and side effects

For independent PRs, separate Servers make the routes explicit. Register each Server's URL for its test flow and keep it across redeployments of that preview. Creating a new PR with this setup still requires configuring its webhook endpoint with the provider.

Separation in Adal Cloud needs to match separation at the source. If a provider sends every event in an account to every registered endpoint, adding more URLs will not isolate the tests. You will need separate test accounts, sandbox projects, or another isolation mechanism supported by that provider.

Multiple Destinations on one Server receive the same incoming Request. That is useful for comparing versions, but it does not automatically select a branch. Naming a Destination PR-184 makes it easier to identify in the dashboard; the name is not a routing rule. Different paths on the same Server do not create isolated event flows with their own Destinations either.

Making webhooks part of the CI/CD lifecycle

Define the webhook route alongside the deployment. The team needs a clear sequence from provisioning to cleanup:

  1. Assign the test flow. Associate the preview with its PR, provider test account, and Server in Adal Cloud. Keep that association across redeployments while the environment serves the same purpose.

  2. Configure the Destination. Set the new application's address and choose Direct HTTP or Adal CLI.

  3. Prepare the application. Run migrations, load test data, and check that the webhook handler is ready. For a private environment, connect the CLI once the application is ready.

  4. Check the complete route. Generate a test event, find the Request, inspect its Delivery, and verify the expected change in the application.

  5. Record what was tested. Include the PR, commit, environment address, and event ID in the QA or CI report. That record ties the event to the code that processed it.

  6. Wind down the event flow. Before removing the preview, stop new events from being sent to it, review pending deliveries, and save any diagnostic information you need.

  7. Remove temporary resources. Stop the CLI, remove the Destination when it is no longer needed, and decide whether to keep the Server and its captured Requests for the remaining retention window.

This is a workflow to incorporate into your deployment process. The automation details depend on your CI/CD platform and the interfaces available from the provider. Start by checking the route with one preview, then make it a repeatable part of deployment.

Supply integration credentials and the CLI token through a secrets store. If CI runs code from external pull requests, define which checks can access those secrets and which trusted environment will run them.

When an event arrives during a deployment

Suppose QA has created a test payment just as the application is being rebuilt. The public Server in Adal Cloud can accept the event while the preview is unavailable. What happens next depends on the delivery route and its settings.

If Direct HTTP reaches an application that is not ready and gets an error or timeout, the outcome appears in the delivery history. Further attempts follow the configured retry policy.

With the CLI, a disconnected client and an unavailable application are different situations. While the CLI is disconnected, no attempt to contact the internal handler begins. If the CLI is connected but cannot reach the application, that counts as a failed attempt.

The Deliver pending requests on connect setting controls delivery of pending Requests when the CLI connects. For this workflow, it must be enabled. The Request must still be stored within retention, the Destination must exist, and the CLI must connect to the correct Server. The handler also needs to be ready.

This can bridge the gap between two deployments of the same preview. The queued event still needs to make sense against the current test data, though. After a database reset, an older webhook may refer to an order that no longer exists.

Using Replay to verify a fix

Some integration bugs are expensive to reproduce. The webhook may arrive only after several steps in a CRM, the completion of an external job, or a particular subscription change. Repeating the whole sequence after every handler change takes time.

With persistent storage, you can inspect a Request, fix the code, and use Replay. Adal Cloud creates a new Request from the stored original and delivers it to the Server's current Destinations. A manual retry repeats a specific existing Delivery. The Request documentation explains the distinction.

For example, QA finds that the handler parses an optional field incorrectly. A developer fixes the code and updates the preview. The team replays the request, checks the Delivery result, and verifies that the application's data now changes as expected.

The test needs the right initial database state and related records. An idempotent handler may skip an event ID it has already processed. That is correct duplicate protection, but testing the revised logic requires a controlled starting state.

Signature rules matter too. A stored request may fail the provider's signature timestamp check; Stripe documents this protection, for example. Adal Cloud does not generate a new provider signature. To test the complete flow with a fresh signature, generate a new test event or use the provider's supported redelivery mechanism.

Handling webhooks after a preview is removed

Closing a PR does not necessarily stop the external service from sending events. An asynchronous operation may finish later, and the provider may still have retries scheduled.

Cleanup needs to cover both the event source and the recipient. Simply repointing the route for PR-184 to PR-185 can send a late event from the first test into the second test's data. Keeping a URL across updates to one environment is useful. Reusing it for a different task requires an explicit decision about the events still in flight.

If you need to investigate after the preview has stopped, you can keep the Server with persistent storage for the required diagnostic window. Deleting a Destination, however, deletes its associated delivery data, including attempt history. Save the information you need first. Deleting the Server also deletes its stored Requests. The storage documentation covers retention and deletion.

Choose retention to fit the testing process. A deployment may be short-lived while the team still needs time to review what happened.

What this gives the team

For a B2B application, testing the interface often covers only part of the workflow. An order, a document status, or a subscription may depend on an event from a payment system, CRM, or processing service. A bug in that part of the flow becomes visible to the customer after the external action has already happened.

Getting webhooks into the right preview lets the team test the integration before merging the branch. QA receives the event in the application instance under review. Developers can inspect the original Request and delivery history. A stored example can help verify the fix.

At Adal Cloud, we separate stable public receipt from delivery to an application that may change. That gives temporary deployments a persistent entry point, parallel branches explicitly separated flows, and QA a record of what arrived and where it was delivered.

Start with one test flow: create a Server in Adal Cloud, configure a Destination for your preview, and check an actual event. The quickstart walks through the setup. Then make provisioning, updates, and cleanup part of the environment's lifecycle.

More from the Adal Cloud blog

Explore product updates, webhook guides, and engineering notes.

Back to blog