API reference
Two calls do the work. Sync, then export.
Every request is authenticated with a bearer API key. All amounts are decimal strings and all dates are ISO calendar dates.
Authentication
Create keys in the dashboard. A key is shown once and stored only as a SHA-256 digest, so a lost key is replaced rather than recovered.
Authorization: Bearer dv_live_XXXXXXXXXXXXXXXXXXXXXXXXEndpoints
- POST
/api/v1/syncImport Stripe balance transactions for a period.
Body: { from, to } as ISO dates; `to` is exclusive so months tile without overlapping. Idempotent — re-running imports only what is new.
- POST
/api/v1/exportsBuild a DATEV Buchungsstapel from imported transactions.
Body: { from, to, bezeichnung?, vatTreatment? }. Returns the export plus the clearing balance and any transactions we could not map.
- GET
/api/v1/exportsList previous exports, newest first.
Cursor paginated with ?limit= (max 100) and ?cursor=.
- GET
/api/v1/exports/{id}One export's metadata.
Scoped to your organisation; an id you do not own returns 404, not 403.
- GET
/api/v1/exports/{id}/fileDownload the EXTF file.
text/csv; charset=windows-1252. The charset matters: reading it as UTF-8 corrupts every umlaut before DATEV sees it.
# Import March, then export it
curl -X POST https://datevbridge.altixcode.com/api/v1/sync \
-H "Authorization: Bearer dv_live_..." \
-H "Content-Type: application/json" \
-d '{"from":"2026-03-01","to":"2026-04-01"}'
curl -X POST https://datevbridge.altixcode.com/api/v1/exports \
-H "Authorization: Bearer dv_live_..." \
-H "Content-Type: application/json" \
-d '{"from":"2026-03-01","to":"2026-04-01","bezeichnung":"Stripe 03/2026"}'What each transaction becomes
Every Stripe transaction produces one or two bookings, all of them against the clearing account. That is what makes the arithmetic checkable.
| Stripe | Soll → Haben | Why |
|---|---|---|
| Charge | Clearing → Revenue | The gross amount, with the VAT key. Never the net Stripe transfers. |
| Fee | Fees → Clearing | Its own booking, so the input tax on it is recoverable. |
| Refund | Clearing → Revenue | Marked Generalumkehr, so turnover is reduced rather than inflated on both sides. |
| Chargeback | Disputes → Clearing | A separate account from fees, so lost revenue stays distinguishable from cost of payment. |
| Payout | Bank → Clearing | Drains the clearing account. After it, the balance is what Stripe still holds. |
Default account mapping
Defaults, not law. Every account is overridable in Settings, and the mapping should be confirmed with your Steuerberater before you rely on it.
| Role | SKR03 | SKR04 |
|---|---|---|
| bank | 1200 | 1800 |
| stripeClearing | 1360 | 1460 |
| revenueStandard | 8400 | 4400 |
| revenueReduced | 8300 | 4300 |
| revenueIntraCommunity | 8125 | 4125 |
| revenueExport | 8120 | 4120 |
| revenueReverseCharge | 8337 | 4337 |
| paymentFees | 4970 | 6855 |
| disputes | 2400 | 6930 |
| roundingDifference | 4820 | 6969 |
| receivables | 1400 | 1200 |
Reading the clearing balance
Every export reports the closing balance of the clearing account. A non-zero value is not automatically wrong — money genuinely in transit across a period boundary shows up here — but it should equal Stripe’s own balance at the end of the period. If it does not, a transaction is missing.
{
"export": { "id": "…", "bookingCount": 42, "clearingBalance": "5.00" },
"clearingBalance": "5.00",
"skipped": [
{ "id": "txn_x", "reason": "Unmapped Stripe transaction type \"topup\"" }
]
}Anything in skipped was deliberately not booked. We do not guess at an account for a transaction type we have not mapped — a plausible guess would hide it, and hiding it is how a ledger goes quietly wrong.
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_payload | The body failed validation. `details.issues` names each field. |
| 401 | missing_api_key / invalid_api_key | No bearer token, or one we do not recognise. |
| 402 | quota_exceeded | The monthly transaction limit is reached. |
| 409 | missing_datev_settings | Beraternummer, Mandantennummer or Wirtschaftsjahresbeginn is not set. |
| 422 | sync_failed | Stripe rejected the key, or it lacks read access to balance transactions. |
| 422 | no_transactions | Nothing is imported for that period. Run a sync first. |
| 422 | reconciliation_failed | A transaction violated an invariant; the message names it. |