Repository navigation
Input Formats
| Format | Example | Notes |
|---|---|---|
| JSON object | one webhook or API response | |
| JSON array | [ {...}, {...} ] |
one record per element |
| JSON Lines | one JSON object per line | typical log export |
| URL-encoded form | status=declined&code=05&amount=10.00 |
lines starting with & are joined, as in many documentation examples |
| Raw HTTP request |
POST /webhook HTTP/1.1 + headers + body |
query parameters are kept as redacted metadata |
| Raw HTTP response |
HTTP/1.1 402 Payment Required + headers + body |
the status code and reason phrase are used, even without a body |
| Callback URL | https://example.com/postback?status=...&id=... |
for GET postbacks that carry data in the query string |
Form bodies are recognized when the content type is application/x-www-form-urlencoded, and also when a provider labels them text/plain or text/html.
Some providers publish JSON examples with trailing commas or // and /* */ comments. If strict parsing fails, PandaPayLens removes only those two things (never inside string values) and tries again. When that works, the analysis shows a LENIENT_JSON warning that names what was removed. Any other syntax error (single quotes, unquoted keys, missing brackets) is not repaired and is reported with its position.
An HTTP error response (status 400 or higher) is analyzed even when its body is not JSON:
-
Plain text, for example
Invalid order status: the status and the text are kept. The text is whitespace-collapsed, scrubbed and capped at 500 characters, and adapters that document such texts can decode them. Because short texts rarely identify a provider, select the provider manually if detection does not pick it. - HTML error pages, for example a proxy's 502 page: the status is kept and the markup is ignored.
- No body at all: the status line alone is analyzed.
Some legacy APIs answer with one name: value pair per line, for example the Verotel FlexPay status page:
response: FOUND
saleID: 13029033
saleResult: APPROVED
Such text becomes one record; repeated names become lists. Pasted alone it needs at least two lines, so a sentence such as Error: not found is not read as data. As the body of a raw HTTP response with Content-Type: text/plain and a status below 400, one line is enough.
One XML document, or an HTTP message with an XML body, becomes one record. Attributes are read as @name, repeated elements as lists, namespace prefixes are removed and the root element and its namespace are kept so adapters can identify the provider. CDATA is read; comments and processing instructions are skipped.
XML is read defensively: a document with a DOCTYPE or any entity declaration is rejected, so external entities and entity expansion cannot happen. Only the five predefined entities and numeric character references are decoded. Nesting depth, element count (50,000) and text length are limited.
Adapters that analyze XML (since 0.11.0; Worldpay since 0.12.0):
| Provider | XML analyzed |
|---|---|
| emerchantpay | Genesis payment_response
|
| Skrill |
refund.pl, pay.pl and ondemand_request.pl responses, API error strings |
| Authorize.net | XML API createTransactionResponse and ErrorResponse (AnetApi namespace) |
| BlueSnap | Payment API card transactions and errors (http://ws.plimus.com namespace) |
| Inpay | ISO 20022 pain.002 and pacs.002 status reports |
| Worldpay | WPG paymentService replies and order notifications, cnpAPI online responses |
XML from other providers is reported as an unsupported record, not as a parse error. ISO 20022 is a generic standard: an Inpay status report is attributed automatically only when it names Inpay as initiating party, otherwise select Inpay manually.
You can paste several inputs at once by dropping multiple files. Each file is a separate source in the timeline.
- XML with a DOCTYPE or entity declarations, for safety. Worldpay WPG documents start with a DOCTYPE line; remove that line before pasting.
- Binary files, PDFs, screenshots.
- Formats an adapter marks as "recognized but not analyzed". The record is identified, and the result says it is not analyzed, instead of guessing.
| Limit | Value |
|---|---|
| One input | 5 MB |
| All files in one analysis | 20 MB |
| JSON nesting depth | 64 |
| Records per input | 5000 |
| Length of one string value | 100,000 |
| Browser analysis time | 20 seconds |
When a limit is exceeded, the analysis stops with a clear error instead of producing partial results silently.
| Code | Meaning |
|---|---|
EMPTY_INPUT |
nothing to analyze |
INPUT_TOO_LARGE |
the input is over the size limit |
INVALID_JSON |
the JSON could not be parsed; the position is shown |
INVALID_HTTP |
the text starts like an HTTP message but is not valid |
INVALID_XML |
malformed XML, or a DOCTYPE or entity declaration; the position is shown |
- Paste the whole HTTP message when the provider puts information in headers or the URL. For example, CCBill sends the webhook event type only in the query string.
- Paste all related events together. Correlation, ordering and most rules need more than one event.
- Keep the original order of a log export. Without timestamps, arrival order is all PandaPayLens can use.
PandaPayLens is open source under the Apache-2.0 license. Demo · Repository · Changelog
Using PandaPayLens
- Getting Started
- Input Formats
- Error Decoding
- Timeline and Correlation
- Diagnostic Rules
- Exports and Reports
- Command Line Interface
Providers
Under the hood
Community