Email this post as a PDFDevelopment · 1 October 2026 · 2 min read

HttpClient in AL: calling external APIs safely

Every integration that leaves Business Central goes through HttpClient. The call itself is six lines; doing it safely is the rest. Headers and authentication, timeouts, reading the status before the body, retries with backoff, where secrets live, telemetry, and the TryFunction boundary that keeps a failed call from taking the transaction with it.

Contents
  1. The call
  2. Around the call
  3. Secrets
  4. Telemetry and the job queue
  5. Cloud rules

Outbound HTTP from AL is simple to write and easy to write badly. This is the shape we use for every outbound call, with the reasons.

The call

[TryFunction]
local procedure TrySend(Url: Text; Body: Text; var ResponseText: Text; var StatusCode: Integer)
var
    Client: HttpClient;
    Request: HttpRequestMessage;
    Response: HttpResponseMessage;
    Content: HttpContent;
    Headers: HttpHeaders;
begin
    Content.WriteFrom(Body);
    Content.GetHeaders(Headers);
    Headers.Remove('Content-Type');
    Headers.Add('Content-Type', 'application/json');
    Request.Content := Content;
    Request.SetRequestUri(Url);
    Request.Method := 'POST';
    Request.GetHeaders(Headers);
    Headers.Add('Authorization', StrSubstNo(BearerTok, GetToken()));
    Client.Timeout := 30000;
    if not Client.Send(Request, Response) then
        Error(NoResponseErr);
    StatusCode := Response.HttpStatusCode();
    Response.Content().ReadAs(ResponseText);
end;

Header names and the bearer prefix are locked labels in a real codebase. Note the content-type must be set on the content's headers, not the request's; it is the most common "415 Unsupported Media Type" cause.

Around the call

procedure Send(Shipment: Record "CON Courier Shipment")
var
    ResponseText: Text;
    Status: Integer;
    Attempt: Integer;
begin
    repeat
        Attempt += 1;
        if TrySend(Setup.GetEndpoint(), BuildBody(Shipment), ResponseText, Status) then
            case Status of
                200, 201:
                    begin
                        StoreResult(Shipment, ResponseText);
                        LogOk(Shipment, Status);
                        exit;
                    end;
                429, 500, 502, 503, 504:
                    Sleep(Attempt * 2000);          // back off, then loop
                else
                    ErrorWithBody(Status, ResponseText);  // 4xx: do not retry
            end
        else
            LogFailure(Shipment, GetLastErrorText());
    until Attempt >= 3;
    Error(SendFailedErr, Shipment."No.");
end;

The TryFunction isolates the transport failure; the caller decides what a status means. Retry only on 429 and 5xx. Never retry a 4xx. Make the operation idempotent on the other side (send your reference; the API should treat a repeat as the same request).

Secrets

API keys and client secrets are not in a setup table field. Online, use Codeunit "Azure Key Vault" via keyVaultUrls in app.json (for ISVs) or, for a per-tenant extension, Isolated Storage (IsolatedStorage.Set/Get with DataScope::Module), entered through a page with a masked field and never displayed back. Tokens are cached in Isolated Storage with their expiry and refreshed before it.

Telemetry and the job queue

Log start, end, status and duration with a correlation ID you also send as a header, so the other side's logs match yours (telemetry). Long or batched sends run from the job queue, not from a user's session, so a slow API does not hold a posting transaction.

Cloud rules

Business Central online allows outbound HTTPS only, and the sandbox has a setting that blocks outbound calls by default after a copy (Allow HttpClient Requests per extension in Extension Management). Document it, because "the integration stopped after the refresh" is that switch.

Email this post as a PDF
A branded PDF of this post, sent to your inbox to keep, print or share. Copy in colleagues if you like.
We only use these addresses to send this PDF. Nobody is added to a mailing list. Mike at Business Boxed receives a copy. See our privacy notice.
Email this post
Talk to us
Want this done in your Business Central?
Book a 30 minute callGet the monthly newsletter

Related posts