Transactions · Partners
Create a transaction
Write settled transactions into Valverna on behalf of merchants. Documents are strictly
validated against the rule pack selected by the business's country and the documentTier —
see the unified schema.
Endpoint
/v1/transactions Partners onlyRequires the transactions.write scope on a vlv_ access token.
All monetary values are integer minor units (cents, öre) — in the request and in the response.
Valverna auto-generates id, createdAt, and source.syncedAt.
Request format
Content-Type optionalUnknown fields optionalFull example
A Swedish café sale in June 2026 — food at the temporary 6% rate, merchandise at 25%,
paid cash so totals.rounding is required.
Request body
{ "type": "sale", "settled": true, "receiptNumber": "R-2026-004521", "timestamp": "2026-06-05T14:32:00+02:00", "currency": "SEK", "locale": "sv-SE", "vendor": { "id": "biz_9f3a2c81", "locationName": "Stureplan" }, // everything else auto-filled "items": [ { "name": "Cappuccino", "quantity": 2, "unitPrice": 4900, "amount": 9800, "taxRate": 6, "taxCategory": "S", "taxAmount": 555, "category": "food_beverage" }, { "name": "Tygkasse med logga", "quantity": 1, "unitPrice": 14900, "amount": 14900, "taxRate": 25, "taxCategory": "S", "taxAmount": 2980, "category": "merchandise" } ], "tax": { "scheme": "SE_MOMS", "pricesIncludeTax": true, "summary": [ { "rate": 6, "category": "S", "label": "Moms 6%", "taxableAmount": 9245, "taxAmount": 555 }, { "rate": 25, "category": "S", "label": "Moms 25%", "taxableAmount": 11920, "taxAmount": 2980 } ] }, "totals": { "subtotal": 24700, "discount": 0, "tax": 3535, "rounding": 0, "total": 24700 }, "payment": { "method": "cash" }, "extensions": { "se": { "controlUnitId": "CU-SE-20241234", "controlCode": "ABCD 1234 EFGH 5678", "sequenceNumber": 4521 } }, "source": { "platform": "acme_pay", "externalId": "pay_9f2a8b1c" }, "metadata": { "invoiceId": "INV-2026-031" } }
profileId and documentTier are omitted here —
they default to the business country's receipt profile (a Swedish business gets se-receipt-1 / receipt).
Root fields
type requiredsettled requiredreceiptNumber requiredtimestamp requiredcurrency requiredprofileId optionaldocumentTier optionalschemaVersion optionallocale optionalmetadata optionalVendor
The stored document carries a full vendor snapshot, but you only send the reference. Everything else — name, legalName, orgNumber, vatNumber, country, address — is auto-filled from the business record at write time.
vendor.id requiredvendor.locationName optionalLine items
The heart of the receipt. At least one item required. All monetary values in minor units.
name requiredquantity requiredunit optionalunitPrice requiredamount requiredtaxRate requiredtaxCategory requiredtaxAmount requireddiscount optionalcategory optionalsku optionalTax
tax.scheme requiredtax.pricesIncludeTax requiredtax.reverseCharge optionaltax.summary requiredtax.jurisdictions optionalTotals
All values in minor currency units.
totals.subtotal requiredtotals.discount requiredtotals.tax requiredtotals.rounding optionaltotals.total requiredPayment
Minimal tender information — the legal floor, not processor data. Required by the SE receipt pack (betalningsmedel is a mandatory receipt field).
payment.method requiredpayment.last4 optionalSource
Provenance — where this transaction came from. Not payment details.
source.platform requiredsource.externalId requiredCustomer
Optional customer-level data — accepted and persisted as-is with the document. Useful for consumer-facing receipt delivery and B2B compliance fields. Every field is optional.
customer.name optionalcustomer.email optionalcustomer.orgNumber optionalcustomer.vatNumber optionalcustomer.country optionalLinked transactions
Required for refund, credit_note, exchange, and void types.
Links back to the original sale.
linkedTransaction.originalTransactionId requiredlinkedTransaction.reason optionallinkedTransaction.note optionalExtensions
Country-specific fields required by tax authorities, namespaced under extensions (this replaces the v2.0 fiscal object).
The se namespace is required under se-receipt-1.
extensions.se.controlUnitId requiredextensions.se.controlCode requiredextensions.se.sequenceNumber requiredValidation errors
Documents are validated against the selected rule pack — arithmetic invariants, required fields,
and rates against the scheme's rate table (date-windowed rate enforcement is planned). Failures return 422 with a list of {field, code, message} issues,
so you can surface every problem in one round trip.
Response 422 Unprocessable Entity
{ "error": { "code": "validation_failed", "message": "2 validation issue(s)" }, "issues": [ { "field": "items[0].taxRate", "code": "invalid_rate", "message": "rate 19.000% is not in the SE_MOMS table effective at 2026-06-05" }, { "field": "totals.rounding", "code": "required", "message": "rounding is required when payment.method is cash (0 when the total already lands on the increment)" } ] }
Deduplication & idempotency
The identity of an ingested transaction is (business, source.platform, source.externalId) as written by your app — dedup is namespaced per writing app, so your writes never collide with Valverna's own
first-party adapters or with other partners. Never receiptNumber.
201 Created First write for this (platform, externalId) pair. The document is stored.
200 OK Replay with the same Idempotency-Key — the existing document is returned unchanged. Safe to retry on network failure.
409 Conflict Same (platform, externalId) posted again with a different (or missing) Idempotency-Key. The transaction already exists — error code duplicate_transaction.
Request header
Idempotency-Key: acme_txn_2026-06-05_a8f2b1c9
The Idempotency-Key is optional and is the
tiebreaker that makes a re-POST of the same source identity a 200 idempotent replay instead of a 409 duplicate. It must be
printable ASCII and at most 255 characters; otherwise the request fails 400 with code invalid_idempotency_key.
Response
Status 201 Created
Returns the full canonical document — your request plus the Valverna-generated id, createdAt, source.syncedAt,
the server-stamped schemaVersion (currently "2.1"),
the resolved profileId and documentTier,
and the embedded vendor snapshot.