
## When to use Outbound {#when-to-use}

Outbound executes HTTP jobs submitted by your application through the Adal API. No incoming Server, Channel or Router is required. Each submission specifies its recipient and region. To forward an accepted webhook, use [Inbound Direct](/en/docs/inbound/direct), not this API.

## Submission flow {#how-it-works}

Application → Adal API → selected region → HTTP recipient. Execution is asynchronous: the API accepts a job, while its outcome and attempts are read separately. The submission response does not synchronously return the recipient's response body.

## Authorization {#authentication}

Create an [API token](/en/docs/common/account-api-tokens) and send it to `https://api.adal.cloud`:

```http
Authorization: Bearer <API-token>
```

The public API base URL is `https://api.adal.cloud`. In the examples, set `ADAL_API_URL` to this value without a trailing slash. Public service connections use HTTPS and WSS.

### Session refresh {#refresh-token}

Use an API token for application requests; signing in to the dashboard does not authorize your application. When an API token expires, issue and configure a replacement.

### Which token to send {#access-token}

Use the account API token's secret, not a Channel CLI token, password or dashboard sign-in credentials. The Outbound dashboard uses its own session; viewing its journal does not require pasting an API token.

## Region {#choose-region}

`GET /outbound/regions` with an API token returns `regions` with the case-sensitive fields `ID`, `Code`, `Name`, `Country`, `City`. Select an actual `ID` and pass it as `region_id`. The recipient URL does not select a region automatically, and an accepted job does not change region. See [Regions](/en/docs/common/regions).

## Submit a job {#send-message}

Use `POST /outbound/requests` with `Content-Type: application/json`. This API path does not accept query parameters. The body is one JSON object; unknown or repeated fields and incorrect types are rejected.

### Job fields {#message-fields}

| Field                | Requirement                                                                             |
|----------------------|-----------------------------------------------------------------------------------------|
| `region_id`          | Required region catalog UUID in canonical lowercase form                                |
| `method`             | Required valid HTTP method                                                              |
| `url`                | Required full HTTP/HTTPS recipient URL; query is allowed, userinfo and fragment are not |
| `headers`            | Required object mapping header names to string arrays; `{}` for no headers              |
| `body`               | Required standard base64 string; `""` for an empty body                                 |
| `idempotency_key`    | Optional nonempty key identifying one logical operation                                 |
| `save_response_body` | Optional boolean, default `false`                                                       |

Send only the submission fields listed above; request identifiers and acceptance times are assigned for you. Do not use `null` for required values. Unlike an Inbound Endpoint base URL, Outbound accepts the full final URL and does not append a Server path.

### Headers {#headers}

For example, `"headers":{"Content-Type":["text/plain"],"X-Demo":["first","second"]}`. Values are arrays, not single strings. Line breaks in values are forbidden. Transport headers, Host and Content-Length are formed for a new connection; client service headers may also be replaced. Do not expect byte-for-byte equivalence of the entire network packet.

### Idempotency key {#automatic-idempotency-key}

Identical calls without a key are not automatically deduplicated. Choose and save a key explicitly, and reuse it only for the same logical submission. Use a new key for a new operation. Checking is scoped to the account and retention period; after expiry the key no longer prevents new execution.

A submission key does not automatically set an `Idempotency-Key` HTTP header at the recipient. If your handler needs that header, supply it explicitly and implement application-side deduplication.

### Body {#request-body}

`aGVsbG8=` is standard base64 for the bytes `hello`. Do not send a nested JSON object as `body`: serialize your data to bytes, then encode it. URL-safe base64 is not a substitute for standard base64. Usage counts decoded bytes, not the base64 string length.

## Acceptance response {#send-response}

Success is `202` with `request_id` and `received_at`. It confirms acceptance, not HTTP success. Save the identifier and read the journal; a record may not appear immediately. A lost response or `503` can leave acceptance uncertain: retry using the same key rather than creating a new logical operation.

## Statuses {#statuses}

`received`, `delivering`, `success`, `failed`, `rejected` and `duplicate` describe different stages and outcomes. HTTP data expiry is a separate flag, not a seventh status. See the [journal](/en/docs/outbound/history) for meanings, filters and `duplicate_of`.

## Attempts {#delivery-retries}

The executor makes automatic attempts until success or completion under execution rules. A `2xx` without an error and with response reading completed correctly is HTTP success; it does not establish a business result. Redirects are not followed automatically. See the shared [retry rules](/en/docs/common/retries).

## Repeated effects {#at-least-once}

A recipient can perform an action before its response is lost. Another HTTP attempt can repeat it even for one accepted job. Submission idempotency and external-effect idempotency are different responsibilities; the service does not promise exactly-once execution.

## Recipient security {#destination-security}

Use a final URL under your control and do not send the Adal API token to the recipient. The executor checks local, private and service destinations; `202` does not mean the URL is allowed and reachable for execution. HTTPS certificates and reachability are checked when connecting.

## History and diagnostics {#history}

Open **Outbound → Requests** in the dashboard. Through the API, read the journal and card by `request_id`. See [diagnostics](/en/docs/outbound/diagnostics) for attempts, wait reasons, network/TLS/HTTP details and snapshot changes, and [HTTP data](/en/docs/outbound/http-data) for bodies.

## Region and retention {#regional-processing}

HTTP data is stored in the selected region. A visible journal record does not mean that its content is still available. Expired content cannot be recovered from the remaining journal row. Retries and reads do not extend retention. See [Storage](/en/docs/common/storage).

## Usage {#credits}

The decoded original body is counted once when the first attempt starts. Responses are not stored by default; with `save_response_body=true`, stored responses from each attempt are added, including failed and incomplete ones. See [Traffic](/en/docs/common/traffic).

## Errors {#troubleshooting}

| Response                | Check                                                                                                        |
|-------------------------|--------------------------------------------------------------------------------------------------------------|
| `400 invalid_request`   | JSON, fields, UUID, URL, header arrays and base64; this is validation failure, not a job's `rejected` status |
| `401`                   | Correct API token, expiration and revocation                                                                 |
| `413 payload_too_large` | Body, envelope and metadata size; the request was not published                                              |
| `503 unavailable`       | Temporary failure or uncertain acceptance; preserve the key when retrying                                    |

Result-read errors `404`, `409` and `410` have other meanings; do not replace a read with another POST. Follow the journal, diagnostics and body guides.

## Boundaries {#limitations}

Bodies, JSON envelopes, metadata, details and downloads have separate constraints. Base64 increases the body size inside JSON: acceptable original bytes do not by themselves establish that the entire envelope fits. The URL and headers also contribute to metadata size. A traffic package does not remove technical limits.

For `413 payload_too_large`, check the original body, entire JSON and metadata sizes; reduce the data sent and remove unnecessary headers. Repeating the unchanged request does not resolve the excess. Invalid format, including an invalid `idempotency_key`, is a `400 invalid_request` issue rather than a size-limit error.

Do not rely on strict ordering, fixed execution time, manual dashboard replay or automatic regional failover.

## Complete integration flow {#complete-flow}

Create an API token → list regions → save an operation key → submit → save the ID → read outcome and attempts → optionally load details and bodies. For uncertain submission, retry the same request with the same key; for a failed read, retry reading.

## API paths {#api-summary}

| Method and path                                                           | Purpose                       |
|---------------------------------------------------------------------------|-------------------------------|
| `GET /outbound/regions`                                                   | Available regions             |
| `POST /outbound/requests`                                                 | Accept a job                  |
| `GET /outbound/requests`                                                  | Journal                       |
| `GET /outbound/requests/{request_id}`                                     | Card                          |
| `GET /outbound/requests/{request_id}/http`                                | HTTP data summary             |
| `GET /outbound/requests/{request_id}/http/details`                        | Details page for one revision |
| `GET /outbound/requests/{request_id}/body`                                | Original request bytes        |
| `GET /outbound/requests/{request_id}/attempts/{attempt_id}/response/body` | Stored attempt response bytes |

## Next {#related-pages}

[Quickstart](/en/docs/outbound/quickstart), [journal](/en/docs/outbound/history), [diagnostics](/en/docs/outbound/diagnostics), [HTTP data](/en/docs/outbound/http-data).
