## What is a Server? {#what-is-server}

A **Server** is the public, region-specific entry point where Adal receives HTTP webhooks. Configure its stable URL in an external service such as GitHub, Stripe, Slack, Telegram, Discord, Dodo Payments, Make, or Zapier.

Every accepted webhook becomes a separate **Request**. Adal records what arrived so that you can inspect the method, path, query string, headers, body, received time, status, and delivery history. If the Server has one or more **Destinations**, Adal creates an independent **Delivery** for each Destination.

```text
External service → Adal Server → Request
                                 ├── Delivery → Destination A
                                 └── Delivery → Destination B
```

Adal preserves the original HTTP method, path, query string, headers, and body. A Server does not rewrite the Request, enrich it with business data, authenticate the sender for your application, or decide how your application should process the event.

## When to use Servers {#when-to-use-servers}

Use a Server when you need a stable and observable place to receive webhooks. Typical uses include:

- developing a webhook handler without exposing your local machine to the internet;
- verifying whether a provider is sending a webhook and inspecting its actual payload;
- replacing temporary tunnel URLs with a stable ingest URL;
- diagnosing delivery failures or temporary Destination downtime;
- sending one Request to multiple Destinations;
- retrying a failed Delivery or replaying a retained Request after changing application code;
- choosing the region where Adal receives and processes request data;
- accepting browser-originated requests, such as form submissions, when CORS is enabled on the Server.

A Server is not permanent storage, a backup or archive, a message queue, an authentication provider, or a security gateway. Keep your own application logs, business records, monitoring, and recovery mechanisms.

## Create a Server {#create-a-server}

Open the [Servers dashboard](https://dashboard.adal.cloud/servers), select **Create server**, and configure the following fields.

**Region**

Choose where Adal should receive and process Requests for this Server. The region becomes part of the public URL and cannot be changed after creation.

**Name**

Enter an internal label that explains the Server's purpose, such as `GitHub development` or `Stripe production`. The name is visible in the dashboard only and does not affect the public URL or request processing.

**Allowed methods**

Select only the HTTP methods you expect. Adal supports `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, and `PUT`. A Request using a method that is not enabled is rejected at intake. Most webhook providers use `POST`, but some use another method for verification or custom workflows.

**IP access restrictions**

Optionally limit which client IP addresses may send Requests to this Server. Choose whether filtering is off, allow only listed addresses and CIDR ranges, or accept all addresses except the listed ones. See [IP access restrictions](#ip-access-restrictions).

**Content-Type restrictions**

Optionally limit which `Content-Type` values are accepted. The filter modes match IP restrictions: disabled, accept only listed types, or accept all except the listed types. Exact types such as `application/json` and subtype masks such as `image/*` are supported. See [Content-Type restrictions](#content-type-restrictions).

**Deliver pending requests on connect**

This setting controls what happens when an Adal CLI client reconnects:

- when enabled, retained pending Requests can be delivered after the CLI connects;
- when disabled, the CLI receives only new Requests that arrive after it connects, and older pending Requests are not delivered automatically on connect.

**Response status code**

Choose the HTTP status that Adal returns to the sender after intake. See [Response returned to the sender](#response-to-the-sender).

**Allow CORS**

Enable CORS response headers when you need browser-originated requests, such as HTML form posts or other front-end calls, to reach the Server. See [Response returned to the sender](#response-to-the-sender).

**Response Content-Type and content**

Choose the `Content-Type` of the response Adal returns to the sender, and optionally provide a static response body. See [Response returned to the sender](#response-to-the-sender).

**Notes**

Use notes for internal context. Notes do not affect intake, delivery, or external integrations. Do not put credentials or webhook payloads in this field.

After saving, copy the Server's public ingest URL. If the dashboard displays a CLI token, save it immediately and treat it as a secret.

## IP access restrictions {#ip-access-restrictions}

IP access restrictions filter Requests by the sender's IP address before the Request enters the normal delivery flow.

Choose one mode:

- **Do not restrict access** — IP addresses are not used for intake filtering.
- **Allow access only from listed addresses** — Adal accepts Requests only from the listed IPv4 addresses, IPv6 addresses, and CIDR ranges. All other sources are rejected.
- **Block access from listed addresses** — Adal accepts Requests from every source except the listed IPv4 addresses, IPv6 addresses, and CIDR ranges.

Enter one address or CIDR range per line. Examples:

```text
203.0.113.10
198.51.100.0/24
2001:db8::1
2001:db8:abcd::/48
```

When a mode other than **Do not restrict access** is selected, the list must contain at least one valid entry. Requests rejected by the IP filter do not enter the normal delivery flow and keep only the minimal troubleshooting record described in [Incoming requests](#incoming-requests).

IP filtering is a Server-level intake control. It is not a substitute for verifying provider signatures or authenticating the sender in your Destination handler.

## Content-Type restrictions {#content-type-restrictions}

Content-Type restrictions filter Requests by the request `Content-Type` header using the same mode pattern as IP filtering.

Choose one mode:

- **Disabled** — `Content-Type` is not used for intake filtering.
- **Accept only listed Content-Types** — Adal accepts Requests only when the request `Content-Type` matches an entry in the list. All other Requests are rejected.
- **Reject listed Content-Types** — Adal accepts Requests unless the request `Content-Type` matches a listed entry.

Enter one Content-Type per line. You can list exact types or use `*` as a subtype mask:

```text
application/json
application/x-www-form-urlencoded
image/*
```

In this example, `image/*` matches types such as `image/png` and `image/jpeg`.

When a mode other than **Disabled** is selected, the list must contain at least one entry. Requests rejected by the Content-Type filter do not enter the normal delivery flow and keep only the minimal troubleshooting record.

Content-Type filtering helps reduce unexpected payloads at intake. Your Destination handler should still validate headers and body before acting on an event.

## Response returned to the sender {#response-to-the-sender}

After Adal accepts an incoming Request at intake, it returns a configured HTTP response to the sending client. This response is separate from Destination delivery: a successful intake response does not mean every Destination completed its work.

### Response status code

Select the status code from the list available in the dashboard:

- `200 OK`
- `201 Created`
- `202 Accepted`
- `204 No Content`
- `400 Bad Request`
- `401 Unauthorized`
- `403 Forbidden`
- `404 Not Found`
- `409 Conflict`
- `422 Unprocessable Content`
- `429 Too Many Requests`
- `500 Internal Server Error`
- `502 Bad Gateway`
- `503 Service Unavailable`

Choose a status that matches what the sending service expects after a successful hand-off. Some providers treat only specific 2xx codes as success.

### Allow CORS

When **Allow CORS** is enabled, Adal returns CORS headers that allow the request origin, including for `OPTIONS` preflight requests. This makes it practical to send browser-originated traffic to the Server, such as HTML form submissions or other front-end HTTP calls.

When CORS is disabled, browser cross-origin requests may fail even if the Server would otherwise accept the same request from a non-browser client.

CORS support does not authenticate the sender and does not replace Destination-side validation.

### Response Content-Type

Choose the `Content-Type` of the response returned to the sender. The dashboard provides common presets:

- `application/json`
- `text/html`
- `text/plain`
- `application/xml`
- `text/xml`
- `application/octet-stream`

You can also select a custom Content-Type and enter a value such as `application/problem+json`.

### Response content

Optionally provide a static response body returned with the intake response. The body is currently fixed text configured on the Server. Dynamic placeholders or variables are not available yet.

Leave the body empty when the chosen status or Content-Type does not require content, or when the sender ignores the response body.

## Server URL {#server-url}

Each Server has a stable public URL for as long as that Server exists. Use the exact URL shown in the dashboard; this documentation uses placeholders only:

```text
https://your-server-id.region.adal.cloud
```

External services can send to the root URL or to a nested path:

```text
https://your-server-id.region.adal.cloud/github/push
```

Query strings are supported:

```text
https://your-server-id.region.adal.cloud/github/push?source=test
```

The path and query string remain part of the same Server and are stored with the Request. They do not create additional Servers.

Do not delete a Server while its URL is still configured in an external service. Deletion makes the URL inactive, and deleted Server subdomains are not reused.

## Regions {#regions}

Every Server belongs to one processing region. The chosen region:

- becomes part of the Server URL;
- receives and processes incoming Requests;
- determines where regional Request data is stored;
- applies to the Deliveries associated with those Requests.

Choose a region that fits your infrastructure, users, sender locations, and data-location requirements. The region cannot be changed on an existing Server. To move to another region, create a new Server there and update the webhook URL in every sending service.

Region availability and the available choices can change. Use the current list shown in the dashboard rather than copying a region identifier from an example.

## Incoming requests {#incoming-requests}

Each accepted incoming HTTP request becomes its own Request. Depending on the Server's storage and retention configuration, you can inspect:

- HTTP method and complete URI;
- path and query string;
- headers and body;
- sender IP address;
- received time and request size;
- status, Deliveries, and attempt history.

Accepted Requests are retained only for the period allowed by the current plan and Server configuration. Where a no-storage or logging-disabled mode is supported and selected, full Request history may not be retained.

A Request can be accepted and visible even when a local application is offline, the CLI is disconnected, or a Destination is temporarily unavailable, provided the Request meets the intake rules and the applicable storage configuration retains it.

Rejected Requests do not enter the normal delivery flow. Adal retains only the method, received time, and rejection reason for troubleshooting. It does not retain their URI, path, query string, headers, body, sender IP address, or delivery data. Rejection can happen for reasons such as a disabled HTTP method, IP access restrictions, Content-Type restrictions, size limits, missing credits, or regional unavailability.

## Paths and query parameters {#paths-and-query-parameters}

One Server can receive related webhook sources on different paths:

```text
https://your-server-id.region.adal.cloud/github/push
https://your-server-id.region.adal.cloud/github/issues
https://your-server-id.region.adal.cloud/github/releases
```

Adal preserves the received path and query string. It does not hide, normalize, or replace them during delivery. This matters when a provider signature includes the request target or when your application routes events by path.

Different paths are not isolated Servers. They share the Server's region, allowed methods, IP and Content-Type restrictions, response settings, limits, retention behavior, and Destinations. Create separate Servers when you need separate public URLs or separate Server-level settings.

## Request limits {#request-limits}

Intake is subject to the current plan and Server configuration. Adal calculates total request size as:

```text
request size = URI size + headers size + body size
```

A long URI or large headers can therefore exceed the limit even when the body is small. A Request can also be rejected when its HTTP method is disabled, the sender IP does not pass IP access restrictions, the request `Content-Type` does not pass Content-Type restrictions, the Server no longer exists, the account cannot accept another Request, or the receiving region cannot accept it.

Rejected Requests use only the minimal troubleshooting record described above. Consult the [current plans and limits](/pricing) instead of relying on values copied into application code or long-lived documentation.

## Credits {#credits}

Credits account for accepted Requests and manual processing actions under the current billing model:

- one accepted incoming Request uses one credit;
- normal storage, automatic delivery attempts, and automatic retries for that Request are included in that credit;
- a rejected Request does not use a credit;
- replaying a Request uses one additional credit;
- manually retrying a Delivery uses one additional credit.

When an account cannot spend the required credit, Adal cannot accept the incoming webhook as a regular Request. Billing rules and plan limits can change, so verify them on the [pricing page](/pricing) and in the dashboard.

## Requests in a Server {#requests-in-a-server}

A Server can receive many Requests. Each accepted HTTP request has its own identifier, received time, status, retention deadline where applicable, and related Deliveries.

```text
Server
├── Request #1
├── Request #2
└── Request #3
```

The existence of a Request confirms that Adal accepted the webhook. It does not mean that every Destination received it or that any downstream business operation completed. Open the Request to inspect each Delivery separately.

Rejected Requests may appear alongside accepted Requests, but contain only minimal troubleshooting information and have no Deliveries.

## Destinations {#destinations}

A Destination tells Adal where to deliver accepted Requests. It belongs to one Server and can use either direct HTTP delivery to a reachable service or Adal CLI delivery to a local or private service.

A Server may have more than one Destination within the current plan limits. Adal creates and tracks a separate Delivery for each Destination, so one route can succeed while another fails.

A Server with no Destinations can still accept Requests for inspection when its storage configuration retains them, but it does not forward those Requests automatically.

Configure connection details, retry behavior, and delivery-specific settings on the Destination rather than on the Server.

## Delivery behavior {#delivery-behavior}

After a Server accepts a Request, Adal creates a Delivery for every configured Destination and records the attempts independently.

```text
Server → Request
         ├── Delivery A → Attempt → 2xx
         └── Delivery B → Attempt → Failure → Retry
```

When a Destination is unavailable or returns a response that requires another attempt, Adal may retry according to that Destination's retry configuration. Automatic retries are part of normal processing. Manual retry is a separate action.

A successful Delivery means Adal received the expected HTTP response from the Destination. It does not prove that the Destination completed a database update, payment action, notification, or other downstream business operation.

Retries, concurrent Destinations, and replay can create duplicate or repeated side effects. Destination handlers should validate input, verify provider signatures, be idempotent, deduplicate by a stable provider event ID where available, and handle partial failures.

## Replay {#replay}

Replay creates a new Request from a previously received Request and sends it through the current Server flow again. The original Request remains unchanged.

```text
Original Request → Replay → New Request → New Deliveries
```

Replay is useful after fixing a handler or when reproducing a delivery problem without waiting for the sender to emit the event again. It is available only while Adal still retains the source data required to recreate the Request.

The replayed Request references the original so that you can distinguish them in the dashboard. Replay is different from manual retry: replay creates a new Request and new Deliveries, while manual retry repeats a specific existing Delivery.

Replay can deliver the same provider event more than once and uses an additional credit under the current billing model. Confirm that every affected handler is safe to run again before replaying.

## Security notes {#security-notes}

A Server URL is public: anyone who knows it can send a matching HTTP request. Treat it as a sensitive integration location, but do not treat possession of the URL as proof of sender identity.

IP access restrictions and Content-Type restrictions reduce unwanted intake, but they are not authentication. Your Destination handler remains responsible for:

- verifying the webhook signature or other authentication evidence supplied by the sender;
- validating method, content type, headers, and payload before acting;
- using constant-time comparison and the provider's documented signing procedure where applicable;
- being idempotent and deduplicating repeated events;
- protecting credentials that can appear in URLs, query strings, headers, or bodies.

Enable only the HTTP methods you expect, configure IP and Content-Type filters when they fit your threat model, and choose an appropriate retention configuration. Enabling CORS widens who can call the Server from a browser; combine it with the other intake controls carefully. Do not copy customer webhook content, Server URLs, tokens, or Destination credentials into ordinary logs, analytics, error reports, or support messages.

Adal preserves the request data needed for signature verification, but your handler must reconstruct and verify the provider's signing input exactly as that provider documents it.

## Delete a Server {#delete-a-server}

Before deleting a Server, remove or replace its URL in every external service that sends to it. Deletion:

- stops new intake for that Server;
- makes its public URL inactive;
- deletes the Server's Destinations;
- does not release or reuse its subdomain;
- does not immediately erase previously accepted Requests, which may remain until their scheduled retention expiry.

Deleting a Server is therefore not a temporary pause. If you only need to stop forwarding while keeping the public URL, remove or disable the relevant Destinations instead.

Review the retained Requests and any replay or audit needs before deletion. Adal is not a permanent archive, so export business records to systems designed for your required retention obligations.

## Troubleshooting {#troubleshooting}

**The webhook is not visible in Adal**

Confirm the complete Server URL and region, verify that the Server still exists, and check allowed methods, IP access restrictions, Content-Type restrictions, total request size, available credits, and regional availability. Look for a rejected record and its reason.

**The Request was rejected**

Check whether the HTTP method is enabled, whether the sender IP passes IP access restrictions, whether the request `Content-Type` passes Content-Type restrictions, and whether the combined URI, headers, and body exceed the current limit. A rejected Request contains only minimal troubleshooting data.

**A browser request fails with a CORS error**

Confirm that **Allow CORS** is enabled on the Server, that the request uses an allowed HTTP method, and that the browser is sending a cross-origin request to the exact Server URL shown in the dashboard.

**The provider reports success, but the response body is unexpected**

Check the Server's response status code, response Content-Type, and static response content. The intake response returned to the sender is configured on the Server and is independent of Destination delivery results.

**The Request exists but was not delivered**

Open its Delivery list. Check that a Destination exists and is enabled, the CLI is connected when required, the target URL is reachable, and the response or error recorded for each attempt. One Destination can fail while another succeeds.

**Pending Requests do not arrive after the CLI connects**

Check **Deliver pending requests on connect** on the Server and confirm that the Requests are still retained and pending. When the setting is disabled, connecting the CLI does not automatically deliver older pending Requests.

**The provider reports an error**

If no Request exists, investigate intake: URL, region, allowed method, IP and Content-Type filters, size, credits, and availability. If the Request exists, investigate the Destination, its attempt history, and the target application. Also compare the configured intake response with what the provider expects.

**You need to stop forwarding but keep the URL**

Do not delete the Server. Remove or disable its Destinations, then confirm the resulting intake and retention behavior matches your requirements.

## Related pages {#related-pages}

- [Quickstart](/docs/quickstart)
- [Core concepts](/docs/concepts)
- [Requests](/docs/requests)
- [Destinations](/docs/destinations)
- [Retries and replay](/docs/retries)
- [Data storage and retention](/docs/storage)
- [Adal CLI](/docs/adal-cli)
