What payload generation covers
The screen collects input. Everything after that point changes it. Fields are added or dropped, numbers are converted, the structure is serialised into a specific byte layout, and the bytes may be encrypted and signed. The server validates that final shape, so a request carrying the right data in the wrong form fails anyway.
Reproducing payload generation means rebuilding the pipeline in code you control, so a client you write produces requests the server accepts without the app running.
Find the last point the app touches the data
Work backwards from the socket. Everything below the place where the final bytes are assembled has to be reproduced. Everything above it you can replace with your own input.
- An OkHttp interceptor sits directly in front of the transport, so it exposes the finished request: method, URL, headers and body buffer.
- A Retrofit converter runs earlier and turns a typed object into bytes. Hooking it shows the object before interceptors add headers or replace the body.
- Other stacks have an equivalent seam. Volley funnels everything through a request class, Ktor has a plugin pipeline, and hand written clients usually keep one method that builds and sends.
- If the body reaches the socket already encrypted, the transformation happens above the transport layer and you need the caller that produced those bytes.
Recover the serialisation rules
Payloads fail for ordinary reasons before they fail for interesting ones. Key order matters when a signature covers the serialised string instead of a canonical form. Optional fields the app omits have to stay omitted, because sending null or an empty string changes the bytes and therefore any hash computed over them.
Details worth checking while you read the code that builds the body:
- Numbers sent as strings, or timestamps sent in milliseconds where the server expects seconds.
- Booleans serialised as integers, which some converters do without being asked.
- Arrays flattened into comma joined strings, or sent as repeated form fields.
- Nested objects reduced to dotted keys, or wrapped in a single envelope key.
- Field order fixed by the class definition rather than by the JSON library.
Print the serialised bytes from the app and from your client and compare them as raw text. A character level diff finds these mismatches faster than reading a specification that may not exist.
Rebuild the values the app derives
Once the shape matches, the remaining work is the values computed at send time rather than read from storage.
- A signature over the method, path, query, body or a subset of headers. Rebuild the exact string that gets hashed, including separators and letter casing.
- Encryption applied to the body, with a key that comes from a hardcoded constant, a value derived from device properties, or material exchanged during login.
- A timestamp inside a validity window, which means your client needs a clock close enough to the server's.
- A nonce or request identifier that must be unique for as long as the server remembers what it has seen.
- A device identifier assembled from build fields, a keystore value, or a token the app registered on first run.
The derivation code is usually short. Finding it is the expensive part, because obfuscation hides the entry points and the working values often sit in a native library or a decoded string table rather than in Java.
Verify one field at a time
A working client is proved by controlled experiments rather than by one successful call. Send the captured request untouched to confirm the endpoint still answers. Then change a single field and watch the response. A field you can alter freely is not validated. A field that breaks the request when altered is part of what the server checks.
Response differences carry information. If a malformed signature produces a different error than an expired one, the server evaluates them at separate points, and you can use those messages to tell which value your client got wrong.
Where the work ends
The result is a function that takes request parameters and returns the exact bytes to send. Wrap it in an HTTP client, keep keys and endpoints configurable, and log the values you derive so a failure points at a specific field instead of at the whole request. Anyone maintaining it later needs to know which values are computed and which are configuration.
Related work
Reviewed 28 September 2026 · SReverse research desk