Integrations and platforms
API and webhook testing
API and webhook testing verifies that a fintech platform's public and partner APIs match their published specification, deduplicate retried requests, sign and redeliver webhooks correctly, and keep older client versions working. Buyers receive a contract test suite, an idempotency and retry behaviour report, webhook signature, ordering, and replay checks, and versioning and backward compatibility checks.
What API and webhook testing covers
A defect in a platform API repeats in every integrator's money flow. A retried payout that the API does not deduplicate pays twice, and a webhook that never arrives leaves an invoice open or a card unfrozen at every client that relies on the event. We test the public and partner APIs of platforms that other fintechs build on, such as banking-as-a-service platforms, acquirers, open banking providers, KYC services, billing, chargeback, and payroll platforms.
Contract tests from the specification
The suite is generated from your OpenAPI document and runs every documented operation. Since OpenAPI 3.1.0 (15 February 2021), a top-level webhooks field describes incoming webhooks that the API consumer may choose to implement, so event payloads get the same schema checks as responses. The current version is OpenAPI 3.2.1, published 10 September 2026.
Checks per operation:
- every documented status code is reachable, and no undocumented status code or field appears;
- required fields, types, formats, and enum values match, including amounts as integer minor units or decimal strings as documented;
- invalid requests return the documented 4xx error body, not a 500;
- pagination, filtering, and tenant scoping return only the caller's records.
A response that drifts from the schema breaks client SDKs generated from that schema. The contract versus end-to-end comparison shows where each test type catches it.
Idempotency keys and retries
RFC 9110 section 9.2.2 does not list POST as idempotent, so a payment or transfer POST needs an application-level key. The IETF Idempotency-Key header draft 07 of 15 October 2025 expired on 18 April 2026 and is not an RFC (checked 2026-09-16). We test against your documented rule and use the draft as the reference where your rule follows it. Test cases:
- Retry after completion. The same key and body return the stored result, success or error, with one side effect (section 2.6).
- Key reused with another body. Section 2.2 says the key MUST NOT be reused with a different payload; section 2.7 says the resource SHOULD reply 422.
- Concurrent retry. A retry sent while the original is still processing SHOULD receive 409 (section 2.7). We send parallel requests to find races that create two records.
- Missing key. An operation documented as requiring the key SHOULD return 400 with a link to documentation (section 2.7).
- Expiry and scope. Section 2.5.2 says resources MUST publish an idempotency specification that includes expiration policy if applicable. We measure the real expiry window and confirm that one tenant's key never returns another tenant's response.
Retries also cover timeouts where the server commits after the client disconnects, and 429 or 503 responses with Retry-After. The payment idempotency testing guide shows the request sequences.
Webhook signatures, ordering, and replay
We test your documented scheme. For platforms that adopt the Standard Webhooks specification (checked 2026-09-16), the checks follow it:
webhook-id,webhook-timestamp, andwebhook-signatureheaders on every event;- a signature over
msg_id.timestamp.payloadwithv1HMAC-SHA256 orv1aEd25519, computed on the raw body; - two space-delimited signatures during secret rotation, with both verifying;
- a redelivery that keeps the same
webhook-id, which the specification recommends consumers use as an idempotency key; - any non-2xx response, including 3xx, counts as a failure to retry, and after
410 Gonethe sender should disable the endpoint.
Ordering tests deliver a refund event before its capture event, and a stale status after a newer one. Each event must carry enough data, such as a resource version or timestamp, for a consumer to discard the stale one. The webhook reliability guide covers receiver-side tests.
Versioning and backward compatibility
The released and candidate specifications are compared operation by operation. Breaking changes include a removed field, a new required request field, a narrowed enum, a changed type, and a changed default. A new enum value in a response is flagged against your version policy, because strict clients reject unknown values. Recorded requests from each supported SDK version replay against the candidate build. Deprecated operations are checked for the Deprecation header of RFC 9745 and the Sunset header of RFC 8594; RFC 9745 section 4 says the Sunset timestamp MUST NOT be earlier than the Deprecation timestamp.
Related
Segments
Standards
Deliverables
Contract test suite generated from the API specification
An automated suite built from your OpenAPI document that sends valid and invalid requests to every documented operation and fails when a status code, header, field, type, or enum value differs from the specification.
Idempotency and retry behaviour report
A report with one row per state-changing operation that records the documented idempotency rule, the observed response to a repeated, altered, concurrent, and expired key, and the count of side effects, for engineering leads and integrating partners.
Webhook signature, ordering, and replay checks
Automated checks that verify each event type's signature, timestamp, event identifier, redelivery after a failed response, and behaviour on duplicate, late, and out-of-order delivery against your documented webhook scheme.
Versioning and backward compatibility checks
A comparison of the released and candidate API specifications and a replay of requests from supported client versions that lists each breaking change, its affected operations, and the deprecation and sunset headers returned.
How API tests fit your release process
Pull requests. The contract test suite runs in your CI against the service built from the branch. A specification diff runs in the same stage, and a pull request that removes a field or narrows an enum without a version change fails with the operation and the breaking change named.
Staging, nightly and before release. Idempotency tests need the real datastore and a fault-injecting proxy that drops responses after the server commits, so they run in staging. The idempotency and retry behaviour report is regenerated each run, and a new operation without a documented key rule appears as an open row.
Webhook receiver. A test receiver in staging records every delivery and returns scripted responses: 500, 3xx, 410, and a response slower than your delivery timeout. Webhook signature, ordering, and replay checks read its log, so retry intervals and event identifiers are compared per attempt.
Before each version release. Versioning and backward compatibility checks replay recorded traffic from each SDK version you still support. Your team decides whether a flagged change ships as a new version or waits for the sunset date.
After release. A smoke run on a sandbox tenant in production sends one idempotent request twice and receives one signed event, and confirms the deployed specification matches the tested one.
Test data. Tests use synthetic tenants, API keys, and webhook secrets. Recorded traffic from production can contain account data and personal data, so it is masked under the procedures on our security page before replay.
Evidence and handover. The suites live in your repository and run without us. CI run logs with the commit, the result, and the approver serve as testing evidence for change management under SOC 2 criterion CC8.1, described on the SOC 2 page. Your team owns the specification, the version policy, webhook secrets, and the release decision.
Sample deliverable
Sample, synthetic data
| Connector | Happy path | Timeout and retry | Expired consent or token | Duplicate, out-of-order, or offline delivery | Coverage status and open defect |
|---|---|---|---|---|---|
| Bank connector 01 (Berlin Group NextGenPSD2) | Covered, 9 of 9 cases passed: POST /v1/consents reaches consentStatus valid after SCA, and the accounts, balances, and transactions calls return 200 for that consent | Covered, 6 of 6 cases passed: a timed-out transactions call is retried with a new X-Request-ID, and a 429 ACCESS_EXCEEDED response stops refreshes for that consent until the next day | Failed, 4 of 5 cases passed: after a 401 CONSENT_EXPIRED response, the connector keeps scheduling refreshes and shows a stale balance of 1,240.00 XTS as current | Covered, 5 of 5 cases passed: a pending transaction that returns with bookingStatus booked and a new transactionId replaces the pending entry, and overlapping dateFrom windows import no duplicates | Failed, retest scheduled after the INT-0203 fix. INT-0203 (medium): the bank connector does not set reconnect required after a 401 CONSENT_EXPIRED response |
| Bank feed 03 (OFX) | Covered, 7 of 7 cases passed: a STMTRQ for a checking account returns STMTRS with SONRS STATUS code 0, and each STMTTRN posts once to the ledger bank account | Covered, 4 of 4 cases passed: a statement request retried after a timeout reuses its TRNUID, and status 2019 Duplicate request is handled as already processed | Covered, 3 of 3 cases passed: SONRS status 15500 Signon invalid stops the bank feed and asks the user to reconnect, with no empty statement imported | Failed, 5 of 6 cases passed: overlapping DTSTART and DTEND windows repeat FITID values, and one repeated FITID with a changed TRNAMT imports as a second transaction | Failed, retest scheduled after the INT-0221 fix. INT-0221 (medium): a repeated FITID with a changed TRNAMT of 18.75 XTS imports as a second bank transaction |
| Card terminal SDK (offline mode) | Covered, 12 of 12 cases passed: online EMV contact and contactless sales return tag 8A value 00, and each approved sale posts one capture | Covered, 6 of 6 cases passed: an authorisation request with no host response before the timeout sends a reversal before the sale is retried | Covered, 4 of 4 cases passed: a terminal session token that expires while the terminal is offline is refreshed before the store-and-forward upload starts | Failed, 10 of 11 cases passed: offline sales under the terminal floor limit (tag 9F1B) complete with tag 8A value Y3, and one retried store-and-forward upload posts two captures | Blocked for release until the INT-0214 fix passes retest. INT-0214 (high): a store-and-forward upload retried after a lost acknowledgement captures one 42.50 XTS sale twice |
| Broker API A (FIX 4.4) | Covered, 10 of 10 cases passed: Logon (35=A) succeeds, and each ExecutionReport (35=8) with ExecType (150) F updates the imported position once | Covered, 5 of 5 cases passed: no inbound message within HeartBtInt (108) triggers a TestRequest (35=1), and a reconnect resumes at the next expected MsgSeqNum (34) | Covered, 3 of 3 cases passed: a Logon with an expired Password (554) is answered with Logout (35=5) and Text (58), and the broker link shows as disconnected with positions kept | Covered, 8 of 8 cases passed: a MsgSeqNum (34) gap triggers ResendRequest (35=2), and a resent ExecutionReport with PossDupFlag (43) Y and a known ExecID (17) is not counted as a second fill | Covered, with no open defects on Broker API A |
| Payout partner B (ISO 20022 pacs.008) | Covered, 8 of 8 cases passed: a pacs.008.001.08 credit transfer with a UETR returns pacs.002 TxSts ACSP and then ACSC, and the payout is marked settled once | Failed, 5 of 6 cases passed: a timed-out pacs.008 submission is followed by a pacs.028 status request, but one retry is sent as a new pacs.008 with a new UETR | Covered, 4 of 4 cases passed: a payout submitted with an expired API access token returns 401, and the token is refreshed before one resubmission with the same UETR | Covered, 6 of 6 cases passed: a pacs.002 TxSts RJCT after ACSP releases the payout hold once, and a repeated pacs.002 for the same UETR changes no balance | Blocked for release until the INT-0230 fix passes retest. INT-0230 (high): a pacs.008 retried after a timeout carries a new UETR and pays 250.00 XTS twice to one beneficiary |
Amounts use XTS, the ISO 4217 code reserved for testing. Connectors, banks, and partners are generic sandbox endpoints, and terminal sales use scheme test cards masked to BIN and last four.
Questions
What is API contract testing?
What is an idempotency key?
How to test webhooks?
Scope your API and webhook testing
Send your OpenAPI document, webhook event list, and version policy, and we return a test scope per operation and event type.
Scope your testing