The Webhook Arrives but Your Handler Rejects It
A third-party service sends you a webhook. Your handler logs "invalid JSON" and returns 400. You copy the raw payload, paste it into a validator, and it parses fine. The problem is likely subtle: double-encoded quotes, a Unicode BOM character, a number where a string is expected, or a missing field your code assumes is always present.
Use OpsCheck JSON Formatter to pretty-print and validate the payload structure. If the payload includes Base64-encoded sections, decode them with OpsCheck Base64 Encoder/Decoder.
Common Webhook JSON Failures
# 1. Check for BOM (Byte Order Mark) — some systems prepend U+FEFF
hexdump -C webhook-payload.txt | head -1
# If you see "ef bb bf" at the start, the payload has a UTF-8 BOM
# 2. Validate with jq — catches syntax errors immediately
cat webhook-payload.txt | jq .
# "parse error: Invalid numeric literal" — means a number field is malformed
# 3. Check if the Content-Type is actually application/json
curl -D - -s -X POST https://example.com/webhook -d '{"test":1}'
# Some services send text/plain with JSON body
Type Mismatches and Missing Fields
# Use jq to inspect specific fields and their types
jq '.event.id, .event.timestamp, .event.data.status' payload.json
# Check if a field is sometimes a string and sometimes a number
# "amount": "100" vs "amount": 100 — both valid JSON, different types
jq 'type' <<< '"100"'
jq 'type' <<< '100'
# Find missing expected keys
jq 'if .event.user == null then "MISSING user" else "OK" end' payload.json
Real-World Scenario
A payment provider webhook started failing after a seemingly minor API version update. The new payload added a "metadata" object that was null when no metadata existed. The handler did: payload.event.metadata.internal_id — which crashed on null. The fix was optional chaining: payload.event?.metadata?.internal_id. The old payload never had the metadata key at all, so the handler had worked for years. The OpsCheck URL Encoder/Decoder helped verify that callback URLs within the payload were properly encoded and not breaking JSON string boundaries.
# Test your handler with edge case payloads
echo '{"event": {"metadata": null}}' | jq '.event.metadata.internal_id'
# jq: error: Cannot index null — same error your handler crashes on
# Safer approach with jq
echo '{"event": {"metadata": null}}' | jq '.event.metadata.internal_id // "N/A"'
Debugging Checklist
- Capture the raw HTTP body before any parsing — not the parsed representation
- Check for BOM, trailing commas, and unicode escape sequences
- Validate with jq or OpsCheck JSON Formatter
- Verify all field types match what your code expects
- Handle null gracefully — any field can be null in a future API version
- Log the raw body at the handler entry point for post-mortem debugging