Xero and Adyen integration
Xero runs the accounting ledger for a small or medium business. Adyen processes the card and online payments behind that business. Connecting the two brings settled payment activity into Xero without re-keying, so captured amounts, refunds, processing fees, and chargebacks land on the right accounts after each Adyen payout. ml-connector handles the different APIs on each side and reconciles payment activity to the Xero ledger on the cadence you set. Because Adyen has no chart of accounts, the general ledger stays in Xero where it belongs.
What moves between them
The flow runs from Adyen into Xero. ml-connector consumes Adyen settlement and reconciliation reports and posts the resulting entries into Xero: captured payments are applied against the matching Xero invoices, while refunds, processing fees, and chargebacks post as bank transactions or manual journals on the correct accounts. Capture, refund, and report-available webhooks trigger the work as soon as activity settles, and a scheduled poll backfills anything a webhook missed. Adyen is treated as a read-only accounting source, so ml-connector never writes payment instructions or ledger entries back into Adyen, and the chart of accounts stays in Xero.
How ml-connector handles it
ml-connector stores both credential sets encrypted. It sends the Adyen X-API-Key on every request and switches to the merchant-specific live URL prefix when the environment is live, since Adyen has no generic live endpoint. On the Xero side it runs the OAuth 2.0 authorization code flow, refreshes the access token before its 30 minute expiry, and sets the Xero-tenant-id header so every call targets the right organization. Adyen webhooks arrive signed with HMAC-SHA256, so each notification is verified against the hmacSignature before processing, and the pspReference is used as the idempotency anchor because Adyen can deliver the same notification more than once. On REPORT_AVAILABLE, the settlement report is downloaded from the signed URL, parsed, and its lines mapped to Xero accounts, which are read first so every entry lands on a valid account code. When a payment matches an open Xero invoice, ml-connector applies it as a payment; fees and chargebacks post as bank transactions or manual journals. Xero has no idempotency key header, so each created record carries its Xero GUID as the upsert anchor and a BullMQ jobId for dedup. Xero rate limits return 429 with a Retry-After header, and Adyen returns a too-many-requests error, so ml-connector backs off and retries on both sides, and every record carries a full audit trail and can be replayed if a Xero post fails.
A real-world example
A direct-to-consumer brand with roughly 40 staff sells through its own online store, takes card payments with Adyen, and keeps its books in Xero. Before the integration, a bookkeeper downloaded the Adyen settlement report each day and hand-entered gross sales, refunds, and processing fees into Xero, then spent the end of every month trying to make the bank deposit match the orders it was meant to cover. The fees were easy to miss, and a single bank line could hide dozens of transactions. With Xero and Adyen connected, each settlement report posts into Xero automatically, payments are applied against the right invoices, and fees and refunds land on their own accounts, so the deposits already reconcile. The daily re-keying step is gone and the monthly close starts from numbers that tie out.
What you can do
- Post Adyen settlement and reconciliation reports into the Xero ledger after every payout.
- Apply captured Adyen payments against open Xero invoices and record refunds, fees, and chargebacks on the correct accounts.
- Verify Adyen capture, refund, and report-available webhooks with HMAC-SHA256 and act on them as activity settles.
- Authenticate Adyen with its API key and live URL prefix, and Xero with OAuth 2.0 and the Xero-tenant-id header.
- Dedupe on the Adyen pspReference and a Xero GUID, with retries and a full audit trail on every record.
Questions
- Which direction does data move between Xero and Adyen?
- The flow is Adyen into Xero. Settlement reports, captured payments, refunds, fees, and chargebacks move from Adyen into the Xero ledger, where captures are applied against invoices and the rest post as bank transactions or journals. Adyen has no chart of accounts and is treated as a read-only accounting source, so ml-connector never writes ledger entries or payment instructions back into Adyen.
- How does the integration get accounting data out of Adyen?
- Adyen exposes no batch pull API for historical transactions, so its settlement and reconciliation reports are the canonical accounting source. ml-connector subscribes to the REPORT_AVAILABLE webhook, downloads each report from its signed URL, parses the lines, and maps them to Xero accounts. Capture and refund webhooks act as real-time triggers, and a scheduled poll backfills anything a webhook missed.
- How are duplicate payments and Xero token expiry handled?
- Adyen can deliver the same notification more than once, so ml-connector uses the pspReference as an idempotency anchor and pairs it with a Xero GUID and a BullMQ jobId before posting, which prevents double-booking. Xero access tokens expire after 30 minutes, so the connector refreshes them proactively from the stored refresh token, and it backs off and retries when either side returns a rate-limit response.
Related integrations
More Xero integrations
Other systems that connect to Adyen
Connect Xero and Adyen
Free to use. Add your credentials, ping your real systems, and see if we fit.
Get started