Invoice Integration Interface v2
Scope
This specification defines a unified, state-of-the-art integration interface for:
- Abacus
- Sage50
- Accounto
It replaces provider-specific coupling with a canonical integration contract and adapter pattern.
Goals
- Single canonical API contract for all finance integrations
- Strict idempotency and replay safety
- Asynchronous, observable processing with job tracking
- Backward-compatible migration from current exporter/importer jobs
- Clear provider adapter boundaries (Abacus, Sage50, Accounto)
Non-Goals
- No direct replacement of provider business rules in phase 1
- No UI redesign in phase 1
Architecture
- Integration API (
/api/integration/v2/*) receives requests and validates payloads - Orchestrator persists command/event records and schedules jobs
- Canonical domain model is the only internal contract
- Provider adapters map canonical model <-> external provider model
- Transport adapters handle REST, SQL/CSV, XML/MQTT specifics
Components
IntegrationControllerIntegrationServiceIdempotencyStoreJobStoreAuditTrailServiceProviderAdapterinterfaceAbacusAdapter,Sage50Adapter,AccountoAdapter
Canonical Domain Model
TenantContext
tenant_id(string, required)client_accounting(string, required)source_system(enum:centraquest,abacus,sage50,accounto)
BusinessPartner
partner_id(string)external_id(string)type(enum:company,person)name(string)address(object)tax_id(string, optional)bank_accounts(array)
InvoiceDocument
invoice_id(string, internal obj_id)barcode(string)invoice_number(string)document_date(date)due_date(date)currency(string, ISO 4217)gross_amount(decimal)net_amount(decimal)tax_amount(decimal)creditor_or_debitor(enum:creditor,debitor)partner(BusinessPartner)line_items(array of LineItem)
LineItem
line_no(integer)account_no(string)cost_center_1(string, optional)cost_center_2(string, optional)tax_code(string, optional)tax_rate(decimal, optional)text(string)amount(decimal)inventory(object, optional)
PaymentStatusEvent
provider_reference(string)invoice_id(string)status(enum:open,partially_paid,paid,rejected)paid_amount(decimal, optional)paid_at(datetime, optional)raw_payload(object)
API Contract (v2)
Base path: /api/integration/v2
1) Export Invoice
POST /tenants/{tenant_id}/providers/{provider}/invoices:export
Headers:
Idempotency-Key(required)X-Correlation-Id(optional)
Body:
client_accounting(required)invoice_id(required)booking_type(creditor|debitor, required)options(optional)
Response:
202 Accepted{ "job_id": "...", "state": "queued" }
2) Export Addresses
POST /tenants/{tenant_id}/providers/{provider}/addresses:export
3) Import Master Data
POST /tenants/{tenant_id}/providers/{provider}/master-data:import
Body:
domains(array:addresses|accounts|taxes|banks|currencies|payment_terms|cost_centers|plants)incremental_since(datetime, optional)
4) Import Payment Status
POST /tenants/{tenant_id}/providers/{provider}/payments:import
5) Job Status
GET /jobs/{job_id}
Response fields:
job_id,provider,operation,state,progress,created_at,updated_at,errors[]
6) Webhook Inbound (optional)
POST /webhooks/{provider}
Security:
- HMAC signature header validation
- replay window check (
timestamp + nonce)
Error Model
All non-2xx responses use RFC7807-style payload:
typetitlestatusdetailinstancecorrelation_idprovider_error(optional)
Idempotency & Consistency
- Every mutating request requires
Idempotency-Key - Key scope:
tenant_id + provider + operation + payload_hash - Duplicate requests return original
job_idand latest state - Outbound provider calls include deterministic external reference when supported
State Model
queuedrunningsucceededfailedpartially_succeededdead_lettered
Retries
- Retryable: network errors, 429, 5xx, transient provider unavailability
- Non-retryable: mapping/validation errors, 4xx semantic errors
- Backoff: exponential with jitter
- Max attempts configurable per provider and operation
Observability
- Structured logs with
correlation_id,tenant_id,provider,job_id - Metrics: success rate, latency, retry count, dead-letter count
- Audit trail entry per state transition and external side effect
Security
- API keys/tokens stored encrypted (no plaintext in logs)
- Least-privilege credentials per tenant/provider
- TLS required for all outbound network calls
- Optional mTLS support for enterprise endpoints
Provider Adapter Requirements
Abacus Adapter
- Support asynchronous XML processing flow (request/result file pattern)
- Support agent transport (MQTT/local process mode)
- Map inventory fields where account starts with 5* (existing behavior)
Sage50 Adapter
- Support SQL/CSV import compatibility
- Support legacy transfer channels while exposing v2 API semantics
- Preserve existing client accounting and period logic
Accounto Adapter
- Use REST API
/v2/{tenant}/{endpoint}style compatibility - Support address upsert, booking export, and payment status sync
- Respect tenant-specific API key handling from
obj_table_invoice_client
Mapping Rules
- Canonical -> provider mapping is explicit and versioned per provider
- Mapping files versioned as
mapping/{provider}/v2/*.yaml - Breaking mapping changes require new mapping version and migration note
Migration Strategy
Phase 1: Parallel Run
- Keep current jobs active
- Introduce v2 API and adapters in shadow mode
- Compare outcomes (existing vs v2) for selected tenants
Phase 2: Controlled Cutover
- Enable v2 per tenant/provider feature flag
- Automatic fallback to legacy flow on critical failure
Phase 3: Decommission Legacy
- Freeze old exporter entry points
- Remove legacy paths after agreed stabilization period
Definition of Done
- v2 endpoints operational for Abacus, Sage50, Accounto
- End-to-end export/import tests per provider
- Idempotency and retry tests green
- Audit and job observability visible in admin tools
- Migration runbook approved
Open Items
- Confirm webhook availability for each provider
- Confirm canonical field ownership for payment references
- Decide final SLA per operation type
- Define tenant onboarding checklist for credentials and validation