cURL Converter

Paste a curl command and get back the request it actually describes — method, URL, query, headers, auth and body — plus working code in eight targets — including PowerShell and wget — and a Postman collection you can import. The command is parsed the way a shell parses it, so quotes inside header and body values survive.

Everything is parsed and generated in this page. A command containing a token never leaves your browser. Backslash line continuations, $'…' strings and nested quotes are all handled.

Paste a curl command to begin.

The parsed request will appear here.

Generated code
Choose an output target and convert.

Want to actually send this request instead of just converting it? Open it in the API Tester — it proxies the call server-side, so CORS never gets in the way.

Build a curl command

curl command
Fill in a URL and press Build.

What a cURL converter is really doing

A curl command looks like a request but is not one. It is a line of shell, and before curl ever sees it the shell has already split it into words, removed quotes, expanded escapes and joined continuation lines. Any tool that claims to convert curl to code has to redo that work faithfully, because the difference between a correct conversion and a subtly wrong one usually lives inside the quoting rather than inside the HTTP.

That is why so many converters break on the same input. Given -H "Authorization: Bearer ab'cd", a converter that finds the outermost quote characters and trims them produces a header value that is either truncated at the apostrophe or carries a stray quote. Given a JSON body with an escaped double quote inside a single-quoted argument, a naive parser resolves the backslash that the shell was supposed to leave alone. Both mistakes are invisible until the generated code runs and the API answers 400 Bad Request or 401 Unauthorized for no obvious reason.

This converter runs a proper quoting state machine over the input first. It understands single quotes (everything literal until the next quote), double quotes (backslash escapes only before ", \, $ and a backtick), unquoted backslash escapes, $'…' ANSI-C strings with their \n, \t, \xHH and \uXXXX forms, and a backslash before a newline as a line continuation rather than an escape. Only once the argument vector is correct does it start interpreting flags.

The flags that change the request

curl has hundreds of options. A small subset determines what goes on the wire, and those are the ones a converter must get right. The rest — output formatting, connection tuning, TLS behaviour — affect the client, not the request, and are reported in the breakdown rather than translated.

FlagEffect on the request
-X, --requestSets the method explicitly. Overrides every inference below.
-H, --headerAdds one header. Repeatable. A trailing ; instead of : sends the header with an empty value.
-d, --dataAdds body content and implies POST. A leading @ means "read this file", and newlines are stripped out of the file as it is read.
--data-rawAs -d but @ is literal. The right choice for JSON.
--data-binarySends bytes verbatim, preserving newlines. Use it when whitespace matters.
--data-urlencodePercent-encodes the value before adding it to the body.
-G, --getMoves all accumulated data into the query string and makes the request a GET.
-F, --formBuilds a multipart/form-data body. @file attaches a file, <file reads a value from one.
-u, --userHTTP Basic credentials, base64-encoded into an Authorization header.
--urlSets the target URL explicitly instead of relying on the bare argument.
-A, -e, -bShorthand for User-Agent, Referer and Cookie headers.
--compressedAdvertises Accept-Encoding and decompresses transparently.
-L, --locationFollows redirects. Affects behaviour, not the first request.

Method inference deserves its own note, because it is where a converted request most often diverges from the original. curl uses GET by default, switches to POST the moment any data or form option appears, and switches back to GET if -G is present — but an explicit -X always wins, even when it contradicts everything else. A command with both -d and -X GET really does send a GET with a body, which some servers accept and many intermediaries silently drop. The breakdown above tells you which rule produced the method it chose. For the semantics behind each verb, see the HTTP methods reference.

There is one implicit header worth watching. If a command carries data but no Content-Type, curl adds application/x-www-form-urlencoded on your behalf. Copy that command into fetch without the header and the browser sends text/plain;charset=UTF-8 instead, and an API that dispatches on content type will reject it. The converter surfaces that implied header explicitly and writes it into the generated code, so the behaviour is preserved rather than inherited by accident. The HTTP headers guide covers the rest of the set that clients add for you.

Escaping, per target

Once the request is parsed, each output language needs its own escaping. Getting this wrong is the second classic failure mode, and it is easy to miss because the generated code usually still looks plausible.

  • JavaScript, Python, Go and Java all accept a double-quoted literal with backslash escapes for ", \ and the control characters, so a JSON-style encoding is correct for all four. An apostrophe needs no escaping at all inside those.
  • PHP is the exception. Double-quoted PHP strings interpolate $variable and {$expr}, so a body containing a dollar sign would be silently mangled. The generated PHP therefore uses single-quoted strings, where only \ and ' need escaping and nothing is interpolated.
  • PowerShell has the same hazard as PHP, from a different direction. A double-quoted PowerShell string expands $var, $(...) subexpressions and backtick escapes, so a JSON body containing $ — or a token that happens to start with one — would be rewritten before the request is ever built. The generated code therefore uses single-quoted strings throughout, which interpolate nothing at all. The one escape that exists inside them is a doubled quote: 'Bearer ab''cd' is the literal Bearer ab'cd. Note that this is not the backslash escaping every other language on this list uses, which is why a converter that reaches for JSON.stringify here produces something that looks right and is not.
  • wget is shell, so it uses the same '\'' idiom as curl itself — the interesting part is the flag mapping rather than the escaping, and it is covered below.
  • Shell, for the reverse builder, uses the single-quote idiom: wrap in single quotes and replace every embedded quote with '\'' — close, escaped quote, reopen. It is ugly and it is the only form that is correct for arbitrary bytes.
  • Postman needs no language escaping because the output is JSON; the values are carried as data rather than as source code, which is exactly why importing a collection is more reliable than pasting a command into a form.

If you are converting a request whose credentials are base64-encoded — Basic auth, most obviously — the Base64 encoder is useful for checking that the value the converter produced decodes back to the username and password you expected. For bearer tokens, decoding the JWT tells you whether the token in your command has already expired, which is a far more common cause of a failing conversion than the conversion itself.

curl to PowerShell, and curl to wget

These two are the most common "same request, different machine" conversions. A curl command copied from a Linux README, a colleague's terminal or a vendor's docs has to run on Windows; or wget is what happens to be installed on the box you are standing in front of. Neither is a straight rename, and both have a default that differs from curl in a way that changes what you observe.

PowerShell

The idiomatic target is Invoke-RestMethod, which sends the request and deserialises a JSON response into a PowerShell object. Use Invoke-WebRequest instead when you care about the status code, the response headers or the raw body — the generated output includes it commented out, since that is normally what you want when you are debugging rather than scripting. Both take -Uri, -Method, a -Headers hashtable and -Body.

Three things reliably go wrong. Quoting is the big one: a double-quoted PowerShell string interpolates $variable and $(expression), so pasting a JSON body containing a dollar sign into double quotes changes the payload silently, which is exactly the class of bug that produces a 400 Bad Request with no obvious cause. Single quotes interpolate nothing, and an embedded single quote is escaped by doubling it rather than with a backslash. Content-Type is the second: it is a restricted header, and Windows PowerShell 5.1 throws "The 'Content-Type' header must be modified using the appropriate property or method" if you put it in the -Headers hashtable, so it belongs on -ContentType. The third is redirectsInvoke-RestMethod follows them by default and curl does not, so the generated command adds -MaximumRedirection 0 unless the original had -L.

One further difference worth knowing rather than discovering: in Windows PowerShell 5.1 a non-2xx response throws a terminating error instead of returning, so a script that expects to read a 404 body needs a try/catch around the call. PowerShell 7 added -SkipHttpErrorCheck, which is the cleaner answer where it is available.

wget

wget and curl look interchangeable and are not. The flag mapping itself is simple — -X becomes --method=, each -H becomes a --header= argument, and the body becomes --body-data= — but two defaults are inverted.

curlwgetWhy it matters
-X POST--method=POSTStraight rename. wget 1.15 and later.
-H 'K: v'--header='K: v'Repeatable in both.
-d '…'--body-data='…'Does not imply POST the way -d does — set the method explicitly.
-u user:pass--user= --password=Or keep the Authorization header the converter already computed.
--compressed--compression=autowget 1.19.2 and later.
-k--no-check-certificateSame meaning, same reasons not to.
writes to stdout-O -wget saves to a file by default. Without this you get a file on disk and an empty terminal.
no redirect follow--max-redirect=0wget follows redirects by default; curl needs -L. Reversed defaults.
prints error bodies--content-on-errorwget discards the body of a 4xx or 5xx unless you ask for it — and that body is usually the error message.

The honest limitation is multipart/form-data: wget has no equivalent of -F and cannot assemble a multipart body. The converter says so rather than emitting something that looks close, because a file upload that silently posts the wrong content type is worse than a command that refuses to be written.

curl to Postman, and back

The Postman target emits a v2.1 collection: an info block with the schema URL, and an item array containing one request with its method, header list, structured URL and body. Import it with Postman's Import → Raw text. A collection rather than a bare request is the deliberate choice here, because a collection is the unit Postman can share, fork, version and run in a collection runner; a loose request is not.

The structured URL matters more than it looks. Postman stores the raw URL and a decomposed protocol, host array, path array and query array. Tools that emit only the raw string produce a request that works but shows an empty Params tab, so variables cannot be substituted per environment and query parameters cannot be toggled. This converter fills in both representations.

Going the other way — Postman or a browser's Copy as cURL to something you can read — is the more common direction in practice, and it is what the breakdown at the top of the page is for. A copied command from Chrome DevTools typically carries fifteen or more headers, most of them browser noise: sec-ch-ua, sec-fetch-mode, accept-language, a cookie jar. Seeing them in a table makes it obvious which two or three actually matter, which is normally the authorization header and the content type. If you are weighing the two tools generally, Postman vs curl covers where each one earns its place, and the Postman alternative page covers running the request without installing anything at all.

From converted command to a request you can actually send

Converting is usually the middle step, not the goal. The goal is to find out what the endpoint returns. Once the breakdown looks right, take the method, URL, headers and body straight into the API Tester and send it. Because that tool forwards the call through our own server rather than issuing it from the page, the browser's same-origin policy never applies and you get the real response from any public endpoint — status, timing, headers and body.

That difference is worth understanding rather than just using. A request issued by JavaScript in a page is subject to CORS; a request issued by curl, by a server, or by any non-browser client is not. Code generated here for fetch will hit that wall if you paste it into a browser console against an API that sends no Access-Control-Allow-Origin — while the identical Python or Go version works first time. If that is the situation you are in, the CORS tester shows you exactly what your browser does with the URL, and CORS explained covers why the failure message is so unhelpful by design.

A last habit worth forming: strip credentials before you share a converted command. Tokens end up in chat logs, issue trackers and pull request descriptions constantly, usually because someone pasted a working curl line to demonstrate a bug. Replace the value with a placeholder, and if a real one has already escaped, rotate it rather than hoping. Anything in the query string is worse still, since it also lands in server access logs and browser history — see API authentication for where a secret should and should not live.

Frequently asked questions

How do I convert a curl command to Postman?

Paste the command above, choose the Postman collection target, and copy the JSON. In Postman use Import and paste it as raw text. The output is a v2.1 collection containing one request, so it imports as a small collection rather than a loose request, which is what makes it shareable and version-controllable. Postman also has its own Import from raw text feature that accepts curl directly; this tool is useful when you want to see the parsed request first, or when you want the same command in code instead.

How do I convert a curl command to PowerShell?

Paste the command and choose the PowerShell target. The output uses Invoke-RestMethod, with headers as a hashtable and the body as a separate variable, plus a commented Invoke-WebRequest form for when you want the status code and raw headers instead of a deserialised object. Every string is single-quoted on purpose: PowerShell does not interpolate inside single quotes, so a dollar sign in a token or JSON body stays literal, whereas a double-quoted string would expand $var and $(...) and silently rewrite your payload. An embedded single quote is escaped by doubling it. Content-Type is passed through -ContentType rather than the hashtable, because Windows PowerShell 5.1 rejects that restricted header when it is set on -Headers.

How do I convert a curl command to wget?

Choose the wget target. The mapping is -X to --method, each -H to a --header argument, and the request body to --body-data. Two defaults differ from curl and the generated command corrects for both: wget writes the response to a file rather than stdout, so -O - is added, and wget follows redirects by default while curl does not, so --max-redirect=0 is added unless the original command had -L. --content-on-error makes wget print an error response body instead of discarding it. One thing wget genuinely cannot do is build a multipart/form-data body, so a command using -F is flagged rather than mistranslated.

Why does my curl command break when a header contains a quote?

Because most converters treat quoting as string trimming rather than shell parsing. A value such as Bearer ab'cd cannot simply be wrapped in single quotes; the shell ends the string at the embedded quote. The correct form closes the quote, emits an escaped quote outside it, and reopens: 'Bearer ab'\''cd'. This converter parses input with a real quoting state machine and escapes output per target language, so a quote in a header or body value survives the round trip.

What is the difference between -d, --data-raw and --data-binary?

-d and --data treat a leading @ as a filename to read, and strip newlines and carriage returns out of that file's content as they read it. --data-raw is identical except that @ is taken literally, which is why it is the safe choice for JSON containing an at sign. --data-binary sends the bytes exactly as given and never interprets @ as a file for you in the same way. All three imply POST and, unless you set Content-Type yourself, imply application/x-www-form-urlencoded.

Does the converted code send the same request as curl?

The method, URL, headers and body are reproduced exactly. What cannot be reproduced is curl's default behaviour around headers each client adds for itself: User-Agent, Accept, Accept-Encoding, Connection and Host differ between curl, fetch, requests and net/http. If a server behaves differently under the generated code than under curl, compare the headers actually sent before suspecting anything else.

Is my curl command sent anywhere?

No. Parsing and code generation happen entirely in this page, so a command containing an API key or bearer token never leaves your browser. If you then want to actually run the request, the API Tester on the homepage does send it through our proxy — that is a separate, deliberate step, and it is described plainly there.

Can it convert a curl command with a file upload?

It parses -F and --form fields and shows them in the breakdown, including which are literal values and which reference a file with the @ prefix. The generated code sketches a multipart body with FormData or its equivalent, but a file part cannot be filled in automatically because the file lives on your machine, not in the command. Those parts are emitted with a clearly marked placeholder.

Related tools and reference