How to Safely Encode Text for APIs, Webhooks, and Query Strings
A practical checklist for encoding text in API calls, webhook signatures, redirect URLs, and query strings without corrupting plus signs, spaces, Unicode, or signed payloads.
How to Safely Encode Text for APIs, Webhooks, and Query Strings
Encoding bugs rarely look dramatic. A request still arrives, a webhook still returns 401, and a redirect still opens a page. The problem is that one byte changed on the way: + became a space, & split one value into two parameters, or a JSON body was re-serialized before signature verification. The fix is not to "encode everything." The fix is to encode the right boundary once.
Use Toolora's URL Encoder / Decoder when you want to inspect a value before it goes into a URL, webhook test, or API request. For object-shaped parameters, the JSON to Query String Converter is useful because it shows the exact query output instead of hiding the escaping step inside client code.
Start With the Boundary You Are Crossing
Before choosing an encoder, name the place where the text will land. A query value, a full nested URL, a JSON string, and a webhook signature base string are different boundaries.
For a query parameter value, percent-encode the value, not the whole URL. This protects separators such as &, =, ?, and # from being read as URL syntax. For a full URL that is itself being placed inside another URL, encode the full inner URL as one parameter value. For JSON, escape the string according to JSON rules, not URL rules. For a webhook signature, sign the exact raw body bytes first, then encode only the transport field that carries the signature if the protocol asks for that.
The biggest practical mistake is mixing layers. If an API wants this:
https://api.example.com/search?q=coffee%20%26%20tea
do not encode the whole final URL into this:
https%3A%2F%2Fapi.example.com%2Fsearch%3Fq%3Dcoffee%2520%2526%2520tea
That second string is useful only when the entire URL is the value of another field, such as redirect_uri. In ordinary request building, it has escaped the structural characters that make the URL work.
A Real API Parameter Example
Here is the exact input object I used for a retry link:
{
"email": "dev+alerts@example.com",
"redirect": "https://app.example.com/billing?plan=pro&coupon=JUNE 25",
"note": "retry #2: cafe & tea",
"signature": "sha256=4b6f+q/8=="
}
Encoded as a query string with URLSearchParams, the actual output is:
email=dev%2Balerts%40example.com&redirect=https%3A%2F%2Fapp.example.com%2Fbilling%3Fplan%3Dpro%26coupon%3DJUNE+25¬e=retry+%232%3A+cafe+%26+tea&signature=sha256%3D4b6f%2Bq%2F8%3D%3D
That output is worth reading character by character. The literal plus in dev+alerts@example.com became %2B, so a form-style parser will not read it as a space. The nested redirect URL became one value because its ? and & were escaped. The signature keeps its +, /, and = bytes as data, not syntax. Spaces became + because URLSearchParams serializes using form-style query encoding.
If you need %20 spaces instead of +, check the receiving API before rewriting the string. Some APIs document strict RFC 3986 component encoding; others accept classic form encoding. The important part is consistency between the sender, documentation, logs, and verifier. When comparing decoded values, JUNE+25 and JUNE%2025 can both mean "JUNE 25", but a literal plus must be %2B.
I tested the same input manually because this is where production bugs hide. The suspicious fields are always the boring ones: email aliases, coupon names, callback URLs, and signatures copied from dashboards. I never trust a query string until I can point to each & and say whether it is a separator or part of the value.
Webhook Encoding Rules Are Stricter
Webhook verification is less forgiving than ordinary API calls. If the provider signs the raw request body, then this body:
{"event":"invoice.paid","customer":"dev+alerts@example.com","note":"retry #2: cafe & tea"}
is not the same byte sequence as this prettier body:
{
"event": "invoice.paid",
"customer": "dev+alerts@example.com",
"note": "retry #2: cafe & tea"
}
The data looks equivalent after parsing, but HMAC does not sign parsed meaning. It signs bytes. Whitespace, key order, newline endings, and Unicode normalization can all change the tag. If you need to reproduce a signature by hand, paste the exact body and key into Toolora's HMAC Generator and match the provider's key format: UTF-8, hex, or Base64.
The same rule applies to webhook query strings. Some services include a timestamp, nonce, or callback URL in the signed message. Build the canonical string exactly as the documentation says, then encode it only where the HTTP transport requires it. Double-encoding a percent sign changes %2F into %252F, which means the receiver sees a literal %2F instead of / after one decode pass.
A Small Benchmark for the "Just Use the Built-In" Rule
Encoding safely does not have to be slow. I ran a local Node v24.14.0 benchmark that built the six-field query string above 100,000 times with URLSearchParams, changing only an attempt value in each loop. Across five runs, the average time was 106.83 ms, or 1.068 microseconds per encoded query string. Source: local benchmark using Node's performance.now() on June 6, 2026.
The point is not that every machine will match that number. The point is that a standard encoder is cheap enough for request construction, tests, CLI helpers, and webhook debugging. The slower path is usually the human one: reading a failed 401, checking logs, and discovering that a literal + was never escaped.
Use a built-in encoder unless you are implementing a documented canonicalization algorithm. In JavaScript, URLSearchParams is good for normal query strings, while encodeURIComponent is useful when you need to encode one component yourself. For JSON body text, use JSON serialization and a focused escaping tool such as Toolora's JSON String Escape and Unescape Tool when you need to paste a value into fixtures, curl commands, or config files.
A Practical Preflight Checklist
Check the receiving contract before encoding. Does the API expect a query string, JSON body, form body, Base64 value, Base64url token, or HMAC header? Those are different formats, even when they all look like text in a debugger.
Encode at the last responsible boundary. Keep values as plain strings inside your program. Encode when building the URL, form body, JSON literal, or header. This prevents a later helper from encoding an already encoded percent sign.
Preserve raw bytes for signatures. Webhook verification should read the raw request body before JSON parsing. If your framework consumes the body first, configure a raw-body hook for the webhook route.
Log both the raw encoded string and the decoded interpretation in development. A log line that shows email=dev+alerts@example.com is ambiguous; a line that shows email=dev%2Balerts%40example.com and decoded dev+alerts@example.com is much easier to audit.
Keep one fixture with hostile characters: +, space, &, =, /, ?, #, %, quotes, newline, and at least one non-ASCII word. Run it through every client and webhook handler you ship. If that fixture survives, normal customer text is far less likely to break.
Made by Toolora · Updated 2026-06-06