PowerShell Invoke-RestMethod POST JSON with a Bearer token
Convert a hashtable with ConvertTo-Json -Depth, then call Invoke-RestMethod -Method Post -ContentType 'application/json' with a Bearer header.

To POST JSON with PowerShell, build the body as a hashtable ([ordered]@{} keeps its key order), convert it with ConvertTo-Json -Depth 10, and send it with Invoke-RestMethod -Method Post -ContentType 'application/json' -Body $json, with the Authorization: Bearer header in -Headers. Leave out -ContentType and a POST goes out as application/x-www-form-urlencoded; leave out -Depth and ConvertTo-Json includes only two levels of nested objects.
PowerShell facts come from Microsoft Learn's Invoke-RestMethod and ConvertTo-Json pages for PowerShell 7.5, and from the Windows PowerShell 5.1 pages listed under Sources. Sume facts come from Create a run, Errors and spend and Authentication. All were read on 2026-09-28. Sume has no PowerShell module: this is a plain HTTPS call.
How do I POST a JSON body with Invoke-RestMethod?
This PowerShell 7 script starts a Sume Format run. The body nests product inside input, which is why -Depth matters; Sume's own create example goes deeper, with a JSON Schema inside output_schema. -Depth accepts up to 100, and PowerShell 7.1 and later warn when the input is deeper than the value you set. Invoke-RestMethod turns the JSON response into objects, so $run.data.id is the run's id.
[ordered] keeps keys in the order you wrote them; Microsoft's about_Hash_Tables page says the order of keys in a plain hashtable isn't deterministic. That matters when you resend: in current code, Sume compares a replayed input with its keys in the order they were sent, so the same data in a different order counts as a different body.
$json = [ordered]@{
instruction = 'Make the weekly promo video.'
input = [ordered]@{ product = [ordered]@{ name = 'Trail mug'; sku = 'MUG-01' } }
communication = @{ webhook_url = 'https://example.com/hooks/sume' }
} | ConvertTo-Json -Depth 10
$headers = @{
Authorization = "Bearer $env:SUME_API_KEY"
'Idempotency-Key' = 'weekly-promo-2026-w40'
}
$run = Invoke-RestMethod -Uri 'https://api.sume.com/v1/formats/acme/weekly-promo/runs' `
-Method Post -ContentType 'application/json' -Headers $headers -Body $json `
-TimeoutSec 30 -SkipHttpErrorCheck -StatusCodeVariable status
if ($status -ge 400) { throw "Sume $status $($run.error.code): $($run.error.message)" }
$run.data.id # 202: new run. 200: replay of the same key and body.How do I send a Bearer token with Invoke-RestMethod?
-Headers takes a hashtable, so @{ Authorization = "Bearer $env:SUME_API_KEY" } works in every version. PowerShell 6.0 and later also have -Authentication Bearer, which requires -Token as a SecureString and overrides any Authorization header you pass in -Headers. Windows PowerShell 5.1 has no -Authentication parameter.
- Sume accepts
Authorization: Bearerorx-api-key, never both. A request carrying both is401 unauthorizedwithSend only one API key credential. - Keep the key in an environment variable or a secret store, not in a committed script. Sume's docs keep API keys on trusted servers, CI secret stores or developer machines.
- Set
-TimeoutSec: its default, 0, waits indefinitely. - In Windows PowerShell 5.1,
curlis an alias forInvoke-WebRequest, so a curl command copied from API docs doesn't run curl there.
How do I read the API's JSON error instead of an exception?
In PowerShell 7, -SkipHttpErrorCheck makes the cmdlet ignore HTTP error statuses and write the error response to the pipeline as if it succeeded, and -StatusCodeVariable stores the status. The script above uses both to read Sume's error envelope: code, message, request_id, retryable and next_action. Windows PowerShell 5.1 has neither parameter, so catch the error with try/catch there. A 4xx at create means nothing ran and nothing was charged: fix the call rather than retrying it.
| Sume answers | Usual PowerShell cause | Fix |
|---|---|---|
415 unsupported_media_type | No -ContentType, so the POST went out as application/x-www-form-urlencoded | -ContentType 'application/json' |
401 unauthorized | $env:SUME_API_KEY is empty in this session, or two credentials were sent | Set the variable; send one credential |
400 unknown_parameter | A misspelled top-level key in the hashtable | Read details.errors[].suggestion |
409 idempotency_conflict | An Idempotency-Key reused with a different body, or with an input hashtable whose keys came out in another order | Use a new key for a new body; build bodies with [ordered] |
413 payload_too_large | A body over 4 MiB | Send media by URL |
Should I use -MaximumRetryCount on a POST?
Not without an idempotency key. -MaximumRetryCount retries whenever the status is between 400 and 599, or 304, so it resends a 400 or 401 that cannot succeed, and it resends paid creates. -RetryIntervalSec sets the pause; on a 429 with Retry-After, the cmdlet waits that long instead. Windows PowerShell 5.1 has neither parameter. Sume's docs say not to retry unsafe submit requests without an Idempotency-Key; with one, a resend is safe:
- Same key, same body:
200with the original run andidempotency_hit: true. No second run, no second charge. - Same key while the first request is still in flight:
409 idempotency_key_in_use, which is retryable after about a second. - Derive the key from what you are making, such as the week, not from a new GUID per call: Sume's docs say a random key per request makes the header decorative. Idempotency keys for AI video APIs covers key design.
Sources
- Create a run
- Errors and spend
- Errors and rate limits
- Authentication
- Microsoft Learn: Invoke-RestMethod (PowerShell 7.5) (read 2026-09-28)
- Microsoft Learn: Invoke-RestMethod (Windows PowerShell 5.1) (read 2026-09-28)
- Microsoft Learn: ConvertTo-Json (PowerShell 7.5) (read 2026-09-28)
- Microsoft Learn: about_Hash_Tables (PowerShell 7.5) (read 2026-09-28)
- Microsoft Learn: Invoke-WebRequest (Windows PowerShell 5.1) (read 2026-09-28)
Related posts
More in Integrations
- Python requests retry: backoff, Retry-After, and POST
Requests doesn't retry by default. Mount urllib3's Retry on a Session with backoff and status_forcelist, and retry POST only with an Idempotency-Key.
- Rails webhooks: verify an HMAC signature in a controller
Read request.raw_post, skip CSRF for that action only, check OpenSSL::HMAC.hexdigest against each sume-v1 entry with secure_compare, then head 204.
- React Native API integration: call an AI video API safely
In React Native, call your own backend with fetch and let it hold the API key. React Native's docs warn that anything in the app bundle is readable.
- Remotion with Claude Code: add AI video, voice and music
Set up Remotion's Agent Skills for Claude Code, then load generated clips, narration and music as files, with TTS word timings as captions.
Written by Sume