Facturen

Tabel facturen · 48 velden

Aanvraag

GET https://app.apiboard.nl/api/v1/wefact/facturen?modified_since=2026-01-01T00%3A00%3A00Z HTTP/1.1
Host: app.apiboard.nl
Authorization: Bearer apib_live_JOUW_SLEUTEL

# Let op: gepagineerd. Herhaal met &cursor=<next_cursor> tot next_cursor null is.
# Deze aanroep haalt alleen rijen op die sinds die datum zijn gewijzigd (ook verwijderde,
# met bron_verwijderd_op). De laatste pagina bevat sync_watermark: geef die bij de volgende
# run mee als modified_since om daarna alleen nieuwe wijzigingen op te halen.
curl -H "Authorization: Bearer apib_live_JOUW_SLEUTEL" \
  "https://app.apiboard.nl/api/v1/wefact/facturen?modified_since=2026-01-01T00%3A00%3A00Z"

# Let op: gepagineerd. Herhaal met &cursor=<next_cursor> tot next_cursor null is.
# Deze aanroep haalt alleen rijen op die sinds die datum zijn gewijzigd (ook verwijderde,
# met bron_verwijderd_op). De laatste pagina bevat sync_watermark: geef die bij de volgende
# run mee als modified_since om daarna alleen nieuwe wijzigingen op te halen.
import json
import os
import requests

TOKEN = "apib_live_JOUW_SLEUTEL"
URL = "https://app.apiboard.nl/api/v1/wefact/facturen"
STAAT_BESTAND = "wefact_facturen_staat.json"  # bewaart rijen + watermark tussen runs

staat = {"watermark": None, "rijen": {}}
if os.path.exists(STAAT_BESTAND):
    with open(STAAT_BESTAND) as f:
        staat = json.load(f)

basis_params = {}
# Alleen wijzigingen: de eerste run vanaf 2026-01-01, daarna telkens vanaf de vorige run
# (inclusief verwijderingen, die hieronder uit de lokale set gaan).
basis_params["modified_since"] = staat["watermark"] or "2026-01-01T00:00:00Z"

cursor = None
onvolledig = set()
while True:
    params = dict(basis_params)
    if cursor:
        params["cursor"] = cursor
    resp = requests.get(URL, params=params, headers={"Authorization": f"Bearer {TOKEN}"})
    resp.raise_for_status()
    body = resp.json()
    for koppeling in body["connections"]:
        if not koppeling["backfill_complete"]:
            onvolledig.add(koppeling["label"])
    for rij in body["data"]:
        staat["rijen"][rij["id"]] = rij  # dedupliceren op id, laatste versie wint
    cursor = body["next_cursor"]
    if cursor is None:
        staat["watermark"] = body["sync_watermark"]
        break

# Rijen die bij de bron verwijderd zijn, uit de lokale set halen.
staat["rijen"] = {i: r for i, r in staat["rijen"].items() if not r.get("bron_verwijderd_op")}

with open(STAAT_BESTAND, "w") as f:
    json.dump(staat, f)

for label in sorted(onvolledig):
    print(f"Waarschuwing: {label} is nog niet volledig gesynchroniseerd; de data kan onvolledig zijn.")
print(f"{len(staat['rijen'])} rijen.")
# Tip: verwijder af en toe (bv. maandelijks) wefact_facturen_staat.json voor een volledige run; een
# hele koppeling die is losgekoppeld, zie je incrementeel namelijk niet.
let
    Basis = "https://app.apiboard.nl",
    Pad = "/api/v1/wefact/facturen",
    Token = "apib_live_JOUW_SLEUTEL",
    Filters = [modified_since = "2026-01-01T00:00:00Z"],

    HaalPaginaOp = (cursor as nullable text) =>
        Json.Document(Web.Contents(Basis, [
            RelativePath = Pad,
            Query = if cursor = null then Filters else Record.AddField(Filters, "cursor", cursor),
            Headers = [Authorization = "Bearer " & Token]
        ])),

    // Volg next_cursor tot die null is; de pagina met next_cursor = null telt ook mee.
    Paginas = List.Generate(
        () => HaalPaginaOp(null),
        each _ <> null,
        each if [next_cursor] = null then null else HaalPaginaOp([next_cursor]),
        each [data]
    ),

    AlleRijen = List.Combine(Paginas),
    Tabel = if List.IsEmpty(AlleRijen)
        then #table({"id", "synced_at"}, {})
        else Table.FromRecords(AlleRijen, null, MissingField.UseNull),
    // Dedupliceer op id (een rij die tijdens de refresh wijzigt, kan twee keer terugkomen):
    // eerst de nieuwste versie bovenaan, dan houdt Distinct die. Verwijder daarna rijen
    // die bij de bron verwijderd zijn.
    NieuwsteEerst = Table.Buffer(Table.Sort(Tabel, {{"synced_at", Order.Descending}})),
    ZonderDubbel = Table.Distinct(NieuwsteEerst, {"id"}),
    ZonderVerwijderd = Table.SelectRows(ZonderDubbel, each Record.FieldOrDefault(_, "bron_verwijderd_op", null) = null)
in
    ZonderVerwijderd

// Let op: het token staat hierboven in de M-query, en dus in het .pbix-bestand zelf -
// wees voorzichtig met het delen van dat bestand.
// Let op: staat een administratie in "connections" op backfill_complete = false, dan is
// die nog niet volledig gesynchroniseerd - de data hierboven kan dan onvolledig zijn.
// Let op: Power BI onthoudt geen stand tussen refreshes. Deze query haalt bij elke refresh
// de rijen op die sinds 2026-01-01 zijn gewijzigd, niet de hele tabel.

Voorbeeldantwoord

{
  "connections": [
    {
      "id": "43d9a41a-3529-4be2-b891-b23781997895",
      "label": "Voorbeeld B.V.",
      "backfill_complete": true
    }
  ],
  "data": [
    {
      "connection_id": "43d9a41a-3529-4be2-b891-b23781997895",
      "connection_label": "Voorbeeld B.V.",
      "id": "314feb6e-f809-4f72-b6d8-da1b68d15ab5",
      "synced_at": "2026-10-07T02:58:12.304211+00:00",
      "bron_verwijderd_op": null,
      "external_id": 42,
      "code": "voorbeeld code",
      "klant_id": 42,
      "klant_code": "voorbeeld klant_code",
      "status": "0",
      "status_label": "Concept factuur",
      "substatus": "voorbeeld substatus",
      "betaling_gepauzeerd_tot": "2026-01-15",
      "betaling_gepauzeerd_reden": "voorbeeld betaling_gepauzeerd_reden",
      "datum": "2026-01-15",
      "betaaltermijn": 42,
      "betalen_voor": "2026-01-15",
      "betaal_url": "voorbeeld betaal_url",
      "bedrag_excl": 125.5,
      "bedrag_btw": 125.5,
      "bedrag_incl": 125.5,
      "bedrag_betaald": 125.5,
      "bedrag_openstaand": 125.5,
      "korting": 125.5,
      "btw_berekenmethode": "voorbeeld btw_berekenmethode",
      "korting_negeren": "voorbeeld korting_negeren",
      "referentienummer": "voorbeeld referentienummer",
      "verzendmethode": "0",
      "verzendmethode_label": "Per e-mail",
      "verzenddatum": "2026-10-07T02:58:12.304211+00:00",
      "verzonden": 42,
      "herinneringen": 42,
      "herinnering_datum": "2026-10-07T02:58:12.304211+00:00",
      "aanmaningen": 42,
      "aanmaning_datum": "2026-10-07T02:58:12.304211+00:00",
      "autorisatie": "voorbeeld autorisatie",
      "betaalmethode": "wire",
      "betaalmethode_label": "Bankoverschrijving",
      "betaaldatum": "2026-01-15",
      "transactie_id": "voorbeeld transactie_id",
      "taalcode": "voorbeeld taalcode",
      "taal_label": "voorbeeld taal_label",
      "valuta": "voorbeeld valuta",
      "omschrijving": "voorbeeld omschrijving",
      "notities": "voorbeeld notities",
      "btw_verlegd": "voorbeeld btw_verlegd",
      "peppol_adres": "voorbeeld peppol_adres",
      "gewijzigd_op": "2026-10-07T02:58:12.304211+00:00"
    }
  ],
  "next_cursor": null,
  "sync_watermark": "2026-10-07T03:00:00.000000Z"
}

De waarden zijn fictief; de vorm komt overeen met wat de API teruggeeft.

Velden in het antwoord

connections
De gekoppelde accounts waar dit antwoord over gaat. Elk account heeft een id, een label en backfill_complete: true betekent dat de eerste volledige synchronisatie klaar is, false dat de data nog onvolledig is.
data
De rijen. Elke rij heeft connection_id en connection_label: uit welk account de rij komt.
next_cursor
Waarmee je de volgende pagina ophaalt. null betekent dat je bij de laatste pagina bent.
sync_watermark
Tot dit tijdstip is de data compleet. Gebruik het als startpunt (modified_since) voor de volgende incrementele ophaalronde.