When to use Outbound
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, not this API.
Submission flow
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
Create an API token and send it to https://api.adal.cloud:
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
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
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
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.
Submit a job
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
| 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
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
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
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
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
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 for meanings, filters and duplicate_of.
Attempts
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.
Repeated effects
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
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
Open Outbound → Requests in the dashboard. Through the API, read the journal and card by request_id. See diagnostics for attempts, wait reasons, network/TLS/HTTP details and snapshot changes, and HTTP data for bodies.
Region and retention
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.
Usage
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.
Errors
| 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
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
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
| 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 |