SReverseby Simpa Labs

Request reproduction

Turning a captured Android request into cURL

A captured request can be transcribed into a cURL command in a few minutes. The command is worth having because it is portable, easy to hand to a colleague, and a useful stepping stone to Postman or Python.

The parts that have to survive the copy

Turning a capture into a cURL command means transcribing four things exactly: the method, the URL including its query string, the header list, and the body bytes. Everything else is presentation. Getting the four right is what makes the command reproducible, and getting any of them approximately right produces a rejection that looks mysterious.

The order matters for a second reason. Rebuilding a request from memory or from a partial capture is the most common way to introduce a difference, so copy the values from the capture rather than retyping them.

Assemble the command in a fixed order

Write the command the same way every time so a diff between two attempts is readable. Start with the method, then the full URL, then one header flag per header, then the body flag, then transport options.

Keep the query string attached to the URL instead of splitting it into data flags. A server that signs the path and query expects them in the original order and encoding, and moving parameters into the body changes both. Single-quote the whole header value, including the space after the colon, so the shell passes it through untouched.

Add the method flag even when it seems redundant, because it documents the request and prevents a body flag from changing the implied method. Then add only the flags the request needs, such as compressed responses or a redirect limit, and leave trust options alone. An insecure flag hides a certificate problem that you want to see.

Get the body right

The body flag you choose decides whether the bytes on the wire match the capture.

  • A JSON body belongs in a data flag that passes the string unchanged, since a flag that strips newlines or reformats the object changes the bytes.
  • A large body is easier to keep in a file and reference, which also avoids shell quoting problems with nested quotes.
  • A form body needs one encoded field per parameter, because encoding each field is what produces the same ordering the server expects.
  • A binary or multipart body needs the flag that preserves bytes and a boundary that matches the capture when the server parses it strictly.

Check whether the capture was stored decompressed. A proxy that decodes a response before showing it can also show a request body that was never sent in that form, and the content length header is the tell.

Values you have to recompute

cURL sends literals. Anything the app derived at request time has to be recomputed before the command runs, and a command with those values frozen is only as durable as the freshness window they carry.

Keep them in shell variables so the command stays readable and you can refresh one value without editing the rest. A short wrapper script that computes the signature and timestamp and then invokes cURL is usually more practical than a single long command, and it turns the capture into something you can run repeatedly during an investigation. When the server enforces a short validity window, the wrapper is the only form that stays useful.

What cURL will not carry

Some parts of the app's behaviour have no equivalent in a command line, and recognising them saves time.

Certificate pinning is the largest. cURL uses the system trust store, so it validates the chain rather than a pinned certificate, and a successful command does not prove the app would accept the same connection. A capture taken through a proxy shows decoded traffic that the app accepted for its own reasons, and it may also have dropped or reordered a duplicate header.

Streaming and long-lived connections are the other boundary. A websocket, a server-sent event stream or a chunked upload does not fit the request and response model a single command assumes, and those need a different tool. So do protocols where the framing carries meaning, such as a gRPC call over HTTP/2.

From a command to a durable client

A working cURL command proves the endpoint, the path and the payload are correct. It is a diagnostic rather than the delivery, because its literals go stale and it cannot refresh a session.

The natural next steps are a collection or a client. SReverse builds an importable Postman collection that recomputes the derived values on each send, which keeps the readability of a command without the frozen literals. If the failure you are chasing is a rejection rather than a transport error, diagnosing 401 and 403 replay failures explains how to read the response, and the same problem from Python covers what changes when the command becomes code.

Reviewed 28 September 2026 · SReverse research desk

Start your full APK reconstruction

Send the full APK

Projects start at $120. Choose WhatsApp or email, then attach the APK in the app that opens. We reply within one hour with the next step and send the fixed quote after review.

Want us to contact you?