# Calling other services

> Two ways to make an outbound HTTP call. A `client` block is a typed wrapper around a known API — name the base URL once, declare each operation as a verb-tagged method. `Http.*` is the facade for a URL you only know at runtime — a webhook, a discovered endpoint. Both hand back an `HttpResponse` you branch on; a non-2xx is a value, not a throw.

<!-- id: http-index · area: http · stability: stable · html: https://osysharp.com/reference/http/index/ -->

## Summary        {#summary}
When your app has to reach *out* to another service — a payment API, a shipping tracker, a webhook — you have two
tools, and which one you pick is decided by a single question: **do you know the API at author time?**

- You know it → a typed [a typed HTTP client (client)](https://osysharp.com/reference/http/client/) block. You declare the shape once and every call site is type-checked.
- You don't (the URL is built at runtime) → the [Http.*](https://osysharp.com/reference/http/facade/) `Http.*`.

Either way the result is an [HttpResponse](https://osysharp.com/reference/http/response/), and a non-2xx status is an ordinary value you branch on — not an
exception you have to catch.

## Description    {#description}

### A typed client for a known API   {#client}
A [a typed HTTP client (client)](https://osysharp.com/reference/http/client/) block is the one to reach for when you're integrating a specific, known API. Inside `client Shipping
{ … }` you name the `BaseUrl` once and declare each operation tagged with its verb (`[Get]`,
`[Post]`, `[Put]`, `[Patch]`, `[Delete]`) and a path — e.g. `[Get("/track/{code}")] TrackResult Track(string
code);`. The request and response bodies are typed, so a call site that passes the wrong shape is a compile error, not
a 4am surprise. It reads like calling a local method; the platform does the HTTP. Full syntax and examples on
[a typed HTTP client (client)](https://osysharp.com/reference/http/client/).

### The facade for a runtime URL   {#facade}
When the URL isn't knowable until runtime — a webhook target stored on a record, an endpoint you just discovered —
use the [Http.*](https://osysharp.com/reference/http/facade/). `Http.Get`/`Post`/`Put`/`Delete` take the URL as a value and return an [HttpResponse](https://osysharp.com/reference/http/response/), so
a webhook call is `var res = Http.Post(webhookUrl, body);` and you branch on `res.IsSuccess`.

### The response is a value, not a throw   {#response}
An [HttpResponse](https://osysharp.com/reference/http/response/) carries the status code, the body as text, and an `IsSuccess` flag (true for 2xx). A non-2xx —
a 404, a 500, a rate-limit 429 — is a normal return you inspect, not an exception. That is deliberate: an outbound
call fails in ordinary, expected ways, and forcing every one through a `try/catch` would be noise. You branch on the
status the same way you'd branch on any other value.

### Credentials belong in secrets   {#secrets}
An API key or client secret an outbound call needs is declared as a [secret](https://osysharp.com/reference/config/secrets/), never inlined. For
signing users in through a third party, or calling an API on a user's behalf, see [OAuth clients (app.OAuthClients)](https://osysharp.com/reference/config/oauth-clients/).

## See also       {#see-also}
- [a typed HTTP client (client)](https://osysharp.com/reference/http/client/) — the typed `client` block and its verb attributes
- [Http.*](https://osysharp.com/reference/http/facade/) — `Http.*` for a URL built at runtime
- [HttpResponse](https://osysharp.com/reference/http/response/) — the status / body / `IsSuccess` result you branch on
- [declaring secrets (app.Secrets)](https://osysharp.com/reference/config/secrets/) — where an API key lives; [OAuth clients (app.OAuthClients)](https://osysharp.com/reference/config/oauth-clients/) — third-party sign-in and delegated calls
