Shopify + Exact Online — boekhouding synchronisatie
Terug naar blog

Shopify + Exact Online — boekhouding synchronisatie

AuthorRuthger Idema
23 juli 20268 min leestijd

Shopify koppelen aan Exact Online voor automatische boekhouding: orders, facturen, BTW-afhandeling en idempotency. App of Laravel maatwerk — wanneer kies je wat?

Shopify + Exact Online — boekhouding synchronisatie

Elke dag dat orders handmatig in Exact Online worden ingevoerd, kost je gemiddeld 8 tot 15 minuten per order. Bij 30 orders per dag is dat al gauw 3 uur boekhoudwerk. Pure overhead. Een Shopify koppeling met Exact Online elimineert dat volledig — maar alleen als je de sync goed inricht. Halfbakken integraties creëren meer problemen dan ze oplossen.

In dit artikel lees je hoe de koppeling technisch werkt, welke opties er zijn (app vs. middleware), hoe je BTW en idempotency goed regelt, en wat er altijd handmatig blijft — ook met de beste sync.


Wat er gesynchroniseerd moet worden

Een Shopify-winkel genereert continu data die boekhoudkundig relevant is. De meeste ondernemers denken alleen aan orders, maar een complete sync omvat meer:

Data-stroomRichtingPrioriteit
Orders (incl. regeldetail)Shopify → ExactHoog
Facturen aanmakenShopify → ExactHoog
Betalingen registrerenShopify → ExactHoog
Creditmemo's / retourenShopify → ExactHoog
Producten / artikelstamdataBidirectioneelGemiddeld
VoorraadExact → ShopifyLaag-gemiddeld
Klantgegevens (debiteuren)Shopify → ExactHoog

Betalingen worden in de praktijk het vaakst vergeten. Een order staat in Exact, maar of er ook betaald is — en via welke betaalmethode — wordt niet altijd meegenomen. Dat geeft een vertekend beeld in je openstaande posten.


App of middleware: de twee routes

Route 1: een kant-en-klare app

De Shopify App Store bevat meerdere integraties voor Exact Online. Denk aan tools als Zapier, OrderCup, of specifieke boekhoudkoppelingen. Deze werken doorgaans via een no-code interface: inloggen, velden mappen, draaien.

Voordelen:
  • Snelle setup (reken op een halve dag tot twee dagen configuratie)
  • Geen ontwikkelkosten
  • SaaS-model: beheer ligt bij de leverancier
Nadelen:
  • Beperkte controle over mapping en businesslogica
  • Doorgaans duurder op schaal (maandelijkse kosten per order of abonnement)
  • BTW-scenarios die afwijken van standaard zijn moeilijk configureerbaar
  • Je bent afhankelijk van de roadmap en stabiliteit van een derde partij

Wij zien bij klanten dat apps goed werken tot een ordervolume van ruwweg 200-500 orders per maand bij standaard BTW-scenarios. Daarboven, of bij B2B-scenario's met afwijkende BTW-regels, loopt het mis.

Route 2: maatwerkkoppeling via Laravel

Voor grotere volumes of complexere businesslogica bouw je de koppeling zelf — of laat je hem bouwen. Laravel is hiervoor de standaard keuze: robuuste queue-infrastructuur, Horizon voor monitoring, en uitstekende ondersteuning voor OAuth2 (wat Exact Online gebruikt).

De Exact Online REST API werkt via OAuth2 met een access token die elke 10 minuten verloopt. Je moet dus token refresh goed inregelen.

php
// Exact Online token refresh via Laravel HTTP client
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;

function getExactToken(string $refreshToken): string
{
    $cacheKey = 'exact_access_token';

    if (Cache::has($cacheKey)) {
        return Cache::get($cacheKey);
    }

    $response = Http::asForm()->post('https://start.exactonline.nl/api/oauth2/token', [
        'grant_type'    => 'refresh_token',
        'refresh_token' => $refreshToken,
        'client_id'     => config('exact.client_id'),
        'client_secret' => config('exact.client_secret'),
    ]);

    $data = $response->json();

    // Access token is 10 minuten geldig — bewaar iets korter
    Cache::put($cacheKey, $data['access_token'], now()->addSeconds(540));

    return $data['access_token'];
}

Met dit patroon voorkom je rate limit-problemen door onnodige token-verzoeken. Exact Online heeft een API-limiet van 300 requests per minuut per divisie — bij hoge ordervolumes loop je daar tegenaan als je niet throttled.


BTW-afhandeling: het lastigste onderdeel

BTW is waar de meeste koppelingen fout gaan. Shopify kent BTW als een percentage op een orderregel. Exact Online werkt met BTW-codes die gekoppeld zijn aan grootboekrekeningen. Die mapping is niet triviaal.

Scenarios die bijzondere aandacht vragen:

B2C Nederland: standaard 21% of 9% per productcategorie. Relatief eenvoudig te mappen. B2B binnen EU (intracommunautaire levering): 0% BTW met verlegging. Shopify stuurt wel een BTW-nummer mee in de orderdata als je de Shopify Markets-configuratie goed hebt staan, maar je moet in Exact de juiste BTW-code gebruiken (doorgaans code 31 of de equivalent in jouw administratie). B2C buiten EU: geen Nederlandse BTW, mogelijk invoerrechten voor de klant. Shopify berekent dit soms al via Duties, maar Exact moet dit als aparte post verwerken. OSS-regeling (One Stop Shop): als je meer dan €10.000 per jaar verkoopt aan EU-consumenten buiten Nederland, geldt het BTW-tarief van het land van de klant. Dit moet per land apart geboekt worden in Exact.

In de praktijk: neem de BTW-mapping nooit over uit een app-template zonder te controleren. Vraag altijd je boekhouder om de exacte BTW-codes en grootboekrekeningen die in jouw administratie gebruikt moeten worden.


Idempotency en foutafhandeling

Dit is het technische onderwerp dat het vaakst wordt overgeslagen — en het vaakst voor dubbele boekingen zorgt.

Idempotency betekent: dezelfde actie meerdere keren uitvoeren geeft hetzelfde resultaat als één keer. Bij een Shopify webhook (order created, order paid, refund created) kan het voorkomen dat Shopify dezelfde webhook meerdere keren stuurt. Als jouw koppeling niet idempotent is, krijg je dubbele facturen in Exact.

De oplossing is simpel: sla per Shopify order-ID op of je hem al verwerkt hebt.

php
// Idempotent order verwerking
use App\Models\ExactSyncLog;

function syncOrderToExact(array $shopifyOrder): void
{
    $orderId = $shopifyOrder['id'];

    // Voorkomen van dubbele verwerking
    if (ExactSyncLog::where('shopify_order_id', $orderId)
                    ->where('status', 'success')
                    ->exists()) {
        return; // Al verwerkt, skip
    }

    // Markeer als in behandeling
    $log = ExactSyncLog::updateOrCreate(
        ['shopify_order_id' => $orderId],
        ['status' => 'processing', 'attempts' => \DB::raw('attempts + 1')]
    );

    try {
        // Verwerk order naar Exact...
        createExactInvoice($shopifyOrder);

        $log->update(['status' => 'success', 'synced_at' => now()]);
    } catch (\Throwable $e) {
        $log->update([
            'status'        => 'failed',
            'error_message' => $e->getMessage(),
        ]);

        // Gooi terug zodat Laravel Queue het herprobeert
        throw $e;
    }
}
Foutafhandeling via queues: gebruik Laravel Queue met exponential backoff. Als de Exact API even niet beschikbaar is (onderhoud, rate limit), wil je automatisch opnieuw proberen — niet een bericht naar de ontwikkelaar sturen die dan handmatig iets doet.
php
// In de Job class
public int $tries = 5;
public array $backoff = [30, 120, 300, 600, 1800]; // seconden

Bij 5 pogingen met deze intervals overleeft de sync een Exact-storing van bijna 30 minuten zonder verlies.


Shopify webhooks vs. polling

Je kunt de Shopify-data op twee manieren ophalen: via webhooks (Shopify pusht naar jou) of via polling (jij haalt periodiek op via de Admin REST of GraphQL API).

Webhooks zijn real-time en efficiënt, maar vereisen een publiek HTTPS-endpoint. Ze kunnen missen als jouw server tijdelijk offline is. Shopify herprobeert mislukte webhooks 19 keer over 48 uur — maar als jouw app in die periode niet beschikbaar is, ben je data kwijt zonder fallback. Polling is betrouwbaarder voor kritische data maar trager en duurder in API-calls. Reken op 15-minutelijks polling als acceptabele vertraging voor boekhoudkundige verwerking. Beste aanpak: webhook als primaire trigger, gecombineerd met nachtelijkse reconciliatie via polling. Orders die via de webhook gemist zijn, worden dan alsnog opgepikt.

Wat handmatig blijft

Eerlijkheid vereist dit te benoemen. Zelfs met een perfecte sync blijft een deel van het boekhoudproces handmatig.

Bankaflettering: Shopify registreert betalingen via betaalproviders (Mollie, Stripe, PayPal), maar de daadwerkelijke bankuitschrijving in Exact moet je nog afletteren. Dit kan deels geautomatiseerd worden via Exact Bank integration, maar niet volledig. Creditnota's bij complexe retouren: een retour waarbij de klant deels terugbetaald krijgt en deels winkelkrediet ontvangt, vereist handmatige beoordeling voor de juiste boeking. Boekingsfouten corrigeren: als er een fout in de sync zit en een factuur in Exact al definitief is gemaakt, kun je die niet via de API aanpassen. Dan is handmatige correctie of creditnota noodzakelijk. Jaarafsluiting en periodeverwerking: Exact-specifieke acties zoals het afsluiten van boekjaren of btw-aangifte doen vallen buiten de scope van de koppeling.

Kosten vergelijking: app vs. maatwerk

SaaS appLaravel maatwerk
Setup kosten€0 - €500€2.500 - €8.000
Maandelijkse kosten€30 - €150/mnd€0 - €50 hosting
Break-evenDirect18-36 maanden
FlexibiliteitBeperktVolledig
OnderhoudLeverancierEigen team / agency
Geschikt voor< 500 orders/mnd, standaard BTW> 500 orders/mnd, B2B, custom flows

De break-even voor maatwerk ligt doorgaans tussen anderhalf en drie jaar. Bij een groeiende Shopify webshop die richting Shopify Plus gaat, is maatwerk bijna altijd de betere keuze op termijn.


Integratie als onderdeel van een grotere architectuur

Een Shopify-Exact koppeling staat zelden alleen. In veel architecturen is er ook een ERP, WMS, of PIM in het spel. Dan wordt de koppeling complexer: wie is de bron van waarheid voor voorraad? Gaat de order eerst via het ERP en daarna naar Exact, of direct?

Bij Shopify Plus-klanten zien wij vaak een middleware-laag die orders ontvangt, verrijkt (met B2B-klantdata, contractprijzen, locatiedata) en daarna doorstuurt naar zowel Exact als het WMS. Die middleware is dan vrijwel altijd een Laravel-applicatie met een duidelijk event-driven model.

Voor complexere scenario's dan een directe Shopify-Exact sync verwijzen we je graag naar onze aanpak voor Laravel maatwerkkoppelingen — of neem contact op voor een architectuurgesprek.


Veelgestelde vragen

Kan ik Shopify koppelen aan Exact Online zonder te programmeren?

Ja, via apps uit de Shopify App Store. Voor standaard scenario's (B2C, Nederlandse BTW, enkelvoudige btw-tarieven) werkt dat prima. Zodra je B2B-klanten hebt met BTW-verlegging, meerdere EU-landen bedient, of boven de 500 orders per maand komt, raad je aan toch maatwerk te overwegen.

Worden retouren automatisch als creditnota in Exact aangemaakt?

Dat hangt af van de implementatie. In een goed gebouwde koppeling luister je naar het refund/create webhook-event van Shopify en maak je automatisch een creditnota aan in Exact. Gedeeltelijke retouren vereisen extra logica om de juiste orderregels te matchen.

Hoe lang duurt het voordat een order in Exact staat?

Met een webhook-gebaseerde koppeling: doorgaans binnen 30 seconden na betaalbevestiging. Met polling: afhankelijk van het interval, maar reken op 15 tot 60 minuten. Voor de meeste boekhoudkundige doeleinden maakt dit verschil niet uit.

Wat als Exact Online offline is tijdens een piekperiode?

Met een queue-gebaseerde implementatie (zoals hierboven beschreven) worden orders gebufferd en opnieuw verwerkt zodra Exact weer beschikbaar is. Zonder queue riskeer je dataverlies. Exact heeft onderhoud doorgaans op werkdagen vroeg in de ochtend — in de praktijk valt dit voor webshops zelden op een piekmomenten.

Ruthger Idema

Geschreven door Ruthger Idema

15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.

Meer over ons team →
Deel dit artikel:

Wil je jouw e-commerce naar het volgende niveau?

Plan een vrijblijvend gesprek met onze experts over Magento, Shopify of Laravel maatwerk.

Plan een Tech Check