A 403 means the request arrived
Treat the status code as information rather than an obstacle. A 403 shows the server parsed your request, identified the endpoint and then refused it. The refusal is a decision, which means something the server expected was missing, stale or wrong. That is a solvable problem, unlike a blocked connection.
What a saved Postman request cannot reproduce
Postman stores literal values. The app calculates them. The gap between those two facts explains most 403 responses on replayed mobile traffic.
- Signatures. If the app signs the method, path, query and body, then any edit in Postman invalidates the signature. Editing a parameter to test something produces a 403 that tells you nothing about the endpoint.
- Timestamps. Servers commonly accept a request only inside a short window. A collection saved yesterday can be correct in every field and still refused.
- Nonces. A value intended to be used once will be rejected on the second send, even seconds later.
- Session state. Tokens and cookies rotate. A stored Authorization header goes stale while the collection stays unchanged.
- Header order and casing. Some servers hash the header block in a specific order. Postman may reorder or normalise headers, which changes the hash.
- Device values. Install identifiers, build fingerprints and keystore-backed values exist only on the device that produced them.
Working the problem in order
Move from the cheapest test to the most expensive, and stop as soon as the response changes.
- Confirm the endpoint answers at all. Send a deliberately wrong token and compare the response with your 403. Different errors mean different checks.
- Send the request twice with no edits. Success then failure indicates a nonce or a one-time value.
- Replace only the timestamp with a current one and leave the signature untouched. A different response means the timestamp is signed.
- Compare the header list in the capture with what Postman transmits. Look for a dropped header rather than a wrong one.
- Check whether the capture was taken from a signed-in state that the collection never establishes.
Why the app is easier than Postman
The app holds the signing key, the clock, the session and the device values in memory. Every call is assembled fresh. Postman is a client without any of that context, so a collection works only when the request has no time-bound or device-bound parts.
When the request does contain those parts, the collection needs a pre-request script that computes them, or the work moves to a small client that can. Both are reasonable. A collection that sends stored values is not.
What a working collection needs
- A pre-request script that recomputes the signature and timestamp for each send.
- Environment variables for the session values that rotate.
- The exact header set the app sends, including headers you consider irrelevant.
- An initial call that establishes the session before the target request runs.
Once the collection reproduces the request from scratch rather than replaying it, the 403 becomes a debugging signal again.
Related work
Reviewed 28 September 2026 · SReverse research desk