Parse Raw HTTP Headers into a Key-Value Object
Paste a raw HTTP headers block and receive a predictable JSON object that is ready for debugging, tests, scripts, or API tooling.
Run — free
Header names are normalized to lowercase, surrounding whitespace is removed from values, and repeated names such as Set-Cookie are preserved in order as arrays instead of being overwritten. Every nonempty line must use the standard Name: Value structure, so malformed input produces a clear error rather than a partially trusted result. The parser is deterministic and runs without network access.
Turn copied header blocks into usable structured data
Browser developer tools, command-line clients, reverse proxies, and server logs often present HTTP headers as plain lines. That representation is easy for a person to scan but awkward for code to query, compare, or store. This parser converts each valid Name: Value line into a property under a single headers object. Names are normalized to lowercase because HTTP field names are case-insensitive, which means Content-Type and content-type resolve to the same property. Whitespace surrounding the value is removed, while colons inside the value remain untouched. That distinction matters for timestamps, URLs, authorization schemes, and other values that legitimately contain punctuation. The result can be copied directly into a fixture, passed to another script, or compared with an expected response. A trailing blank line is accepted because copied HTTP header sections commonly end with the empty separator that precedes a message body. Blank or malformed lines inside the block are rejected so an incomplete parse cannot quietly look successful.
Preserve duplicate headers instead of losing information
A plain JavaScript object normally stores one value per key, so a simplistic parser overwrites earlier values whenever a name appears twice. That behavior can silently discard meaningful protocol data. This capability returns a string when a header occurs once and changes that property to an array when the same case-insensitive name occurs again. Additional occurrences are appended in their original order. The rule works for Set-Cookie, Warning, Link, and any other repeated field without attempting to combine values using commas. Avoiding automatic comma joining is intentional: different header fields have different combination rules, and Set-Cookie in particular must not be treated like a generic comma-separated list. An empty value is still valid when the colon is present, so X-Optional: becomes an empty string rather than an error. The parser does not interpret dates, cookies, media types, quality weights, or authentication credentials. It preserves field values as text, leaving protocol-specific interpretation to the component that understands that header.
Detect malformed lines early and use the result safely
Reliable parsing is as much about rejection as conversion. Each input line must begin with a valid HTTP field name, immediately followed by a colon and then its value. Field names may contain the token characters allowed by HTTP, but they cannot contain spaces, tabs, parentheses, separators, or leading whitespace. Obsolete folded continuation lines are rejected rather than attached to the previous value, which prevents ambiguous results and encourages callers to provide a modern normalized header block. When validation fails, the error identifies the relevant line and explains whether the pair or the name is invalid. No partial object is returned. This makes the capability useful in import pipelines and automated tests where accepting half of a block would be worse than stopping. Processing is local and deterministic: there are no network requests, time-dependent fields, random values, or external lookups. The same text therefore produces the same JSON structure in browser use and through the API, whose base request price is $0.002.
What you can do with it
Build API test fixtures
Convert headers copied from an HTTP trace into structured JSON that can be checked into a deterministic response fixture.
Inspect repeated response fields
Keep every Set-Cookie, Link, or Warning occurrence in order instead of losing earlier values during object conversion.
Validate imported diagnostics
Reject malformed header lines before a pasted log excerpt enters a debugging, support, or observability workflow.
FAQ
How are duplicate header names represented?
A name with one occurrence maps to a string. When it occurs more than once, its value becomes an array in input order.
Are header names case-sensitive?
No. Names are normalized to lowercase, so Content-Type and content-type are treated as the same header.
Can a header value contain a colon?
Yes. Only the first colon separates the name from the value; every later colon remains part of the value.
What happens when a line is malformed?
The entire request fails with an invalid input error that identifies the line. A partial headers object is never returned.
Does the parser split cookies or comma-separated values?
No. Values remain text exactly apart from surrounding whitespace. Repeated physical lines are represented as arrays.
What does API use cost?
The base price is $0.002 per request. The browser version runs locally without sending the header block over the network.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/dev2/http-header-parse \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Content-Type: application/json\r\nCache-Control: no-cache\r\nSet-Cookie: theme=dark\r\nSet-Cookie: session=abc123"}'const res = await fetch("https://api.kit.forhosting.com/dev2/http-header-parse", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "Content-Type: application/json\r\nCache-Control: no-cache\r\nSet-Cookie: theme=dark\r\nSet-Cookie: session=abc123"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev2/http-header-parse",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "Content-Type: application/json\r\nCache-Control: no-cache\r\nSet-Cookie: theme=dark\r\nSet-Cookie: session=abc123"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev2/http-header-parse", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"Content-Type: application/json\\r\\nCache-Control: no-cache\\r\\nSet-Cookie: theme=dark\\r\\nSet-Cookie: session=abc123"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"Content-Type: application/json\r\nCache-Control: no-cache\r\nSet-Cookie: theme=dark\r\nSet-Cookie: session=abc123"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev2/http-header-parse", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "Content-Type: application/json\r\nCache-Control: no-cache\r\nSet-Cookie: theme=dark\r\nSet-Cookie: session=abc123"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev2.http_header_parse",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |