C# HttpClient POST JSON with a Bearer token
Set Authorization with AuthenticationHeaderValue("Bearer", key), send a JSON body, then read the status and body before EnsureSuccessStatusCode.

To POST JSON with a Bearer token in C#, set request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token) (or the same on HttpClient.DefaultRequestHeaders), send the body as StringContent with the media type application/json or with PostAsJsonAsync, then read the status code and the body. Read the body before you call EnsureSuccessStatusCode(), because that call throws on any status outside 200-299 and the API's error message is in the body.
HttpClient facts come from Microsoft Learn: Make HTTP requests with HttpClient, PostAsJsonAsync, HttpClient.Timeout and AuthenticationHeaderValue. The example API is Sume's, from Authentication, Video Generation, Errors and rate limits and Jobs and results, all read on 2026-09-29. Sume's only documented client library is the TypeScript SDK, so from C# this is a plain HTTPS call.
How do I send a JSON POST with a Bearer token in HttpClient?
Build an HttpRequestMessage when a header changes per request, such as an Idempotency-Key. This example starts a Sume video job. The key comes from an environment variable on the server; Sume's docs say not to place API keys in frontend JavaScript or mobile apps.
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; // reuse one instance
var json = JsonSerializer.Serialize(new {
model = "sume/auto",
prompt = "A vertical product clip on a desk, natural light",
aspect_ratio = "9:16",
duration = 5
});
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.sume.com/v1/videos") {
Content = new StringContent(json, Encoding.UTF8, "application/json")
};
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("SUME_API_KEY"));
request.Headers.Add("Idempotency-Key", "order-8823-clip-v1");
using var response = await http.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
throw new InvalidOperationException($"{(int)response.StatusCode}: {body}");
// 202: body has id, polling_url and status "pending"Should I use PostAsJsonAsync or StringContent?
Either works. PostAsJsonAsync is an extension method in the System.Net.Http.Json package that serializes a value as JSON into the request body, and ReadFromJsonAsync<T>() deserializes the reply. It takes a URL and a value, so per-request headers need HttpRequestMessage and SendAsync as above. When the token is the same for every call, set it once on DefaultRequestHeaders.Authorization and use PostAsJsonAsync.
Microsoft recommends reusing HttpClient instances for the application's lifetime, as a static field or through the HTTP client factory, rather than creating one per call.
What status codes should my C# code handle?
IsSuccessStatusCode is true for 200-299, which covers 202 Accepted. Sume's error bodies share one envelope, { "error": { "code", "message", "request_id", "details" } }, and the request id is safe to share with support. Log error.code and error.request_id rather than only the status.
| Status | Code | What it means for the C# caller |
|---|---|---|
202 | — | The job was accepted: store id and poll polling_url |
400 | invalid_request | Body, query, path or headers are invalid; fix the call |
401 | unauthorized | Key missing or invalid, or both Authorization and x-api-key were sent |
402 | insufficient_credits | The balance can't cover the generation |
415 | unsupported_media_type | The body wasn't application/json |
429 | rate_limited or queue_full | Back off; use retry-after when present |
Why does my HttpClient POST time out?
HttpClient.Timeout defaults to 100 seconds and applies to every request on that instance; a CancellationTokenSource can set a shorter one per request. On timeout, HttpClient throws a TaskCanceledException whose inner exception is a TimeoutException.
For a job API, don't raise the timeout to the length of the work. Sume's video create returns the job id at once, and generation runs asynchronously; you poll GET /v1/videos/{id} until the status is completed. A client-side timeout does not cancel a job: it keeps running and still bills. Polly retry for HttpClient POST covers retrying safely.
How do I stop a retry from paying twice?
Send an Idempotency-Key on every paid create and build it from the thing being made, such as an order id plus a version, not from Guid.NewGuid() per attempt. On /v1/videos, a replay with the key returns the original job. Sume's docs say not to retry unsafe submit requests without one. Idempotency keys for AI video APIs covers the replay answers, and curl bearer token shows the same call from a shell.
Sources
- Authentication
- Video Generation
- Errors and rate limits
- Jobs and results
- Microsoft Learn: Make HTTP requests with the HttpClient class (read 2026-09-29)
- Microsoft Learn: HttpClientJsonExtensions.PostAsJsonAsync (read 2026-09-29)
- Microsoft Learn: HttpClient.Timeout (read 2026-09-29)
- Microsoft Learn: AuthenticationHeaderValue (read 2026-09-29)
Related posts
More in Integrations
- Cursor team MCP servers: share Sume's hosted MCP across a team
Cursor's docs describe project, global and team MCP servers. Where Sume's hosted MCP fits in each, how sign-in works per person, and what a shared key changes.
- EventBridge API destinations: call a paid API without Lambda
An EventBridge API destination calls an HTTPS API straight from a rule, with a 5-second timeout and retries on 409, 429 and 5xx. Key every call.
- Golang HTTP POST JSON with headers and a Bearer token
http.Post can't set headers. Marshal the JSON, build it with http.NewRequest, set headers, send with a Client that has a Timeout, and close the body.
- GPT-6 Sol and Luna in Codex: keep your Sume MCP server across models
Codex added GPT-6 Sol and Luna to its model picker in late September. Your Sume MCP server is configured per Codex, not per model, so switching needs no change.
Written by Sume