Démarrage rapide
1. Authentification — émettre un PAT
Section intitulée « 1. Authentification — émettre un PAT »Tous les appels /api/v1 s’authentifient en Bearer avec un PAT (Personal Access Token). Émettez-le depuis la console, ou depuis l’API avec une session déjà connectée (JWT).
curl -X POST https://d2b.dev/api/v1/me/tokens \ -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \ -d '{"name": "my-agent", "scopes": ["workbooks:read", "workbooks:write"]}'# → {"token": "d2b_pat_...", ...} (the token is shown in plaintext only in this response)- Les scopes sont ressource×action :
workbooks:read/write/delete,cloud-files:read(lister / importer depuis Drive / OneDrive — par défaut pour les logins, explicite pour les PAT),governance:configure,workspaces:read/create/configure/delete,keys:read/mint/revoke,account:read,billing:manage. L’implication reste dans une ressource (write ⊃ read) ; supprimer un workbook, restaurer un snapshot ou revenir à une version requiertworkbooks:delete - Un token est toujours lié à exactement un compte (un token = un compte). Émis depuis une session connectée, il vise votre compte par défaut ; passez
account_idpour viser l’un de vos comptes développeur.GET /api/v1/merenvoieaccount_id/account_name resourcerestreint la portée :workbook:<id>(ce seul workbook — la forme recommandée quand le token est confié à un agent) ouworkspace:<id>(les workbooks de ce workspace seulement ; les créations y atterrissent aussi). La valeur par défautaccountcouvre tout le compte. Seulresourcefixe la portée ; les scopes disent ce que la clé peut faire — une clé sansworkspaces:readcrée quand même dans n’importe quel workspace de son compte si elle est épinglée àaccount. Nommer dansworkspace_idun workspace hors de portée renvoie 403, à la liste comme à la créationGET /api/v1/me/workspacesliste les workspaces atteignables, avec leur nom (is_default= destination d’une création sansworkspace_id)./meet la liste des workbooks portent aussiworkspace_name- Le provisionnement de workspaces est
workspaces:create, l’émission de cléskeys:mint, les opérations de facturationbilling:manage— les permissions sont des scopes ressource×action indépendants, sans scope parapluie ; émettez des clés portant exactement ce qu’il leur faut (style GitHub fine-grained PAT) - Une création sans
workspace_idatterrit dans le plus ancien workspace du compte du token (le workspace personnel pour le compte par défaut). Un compte développeur sans workspace renvoie 409 — créez-en un d’abord dans la console (Workspaces) ou avec une cléworkspaces:create(POST /api/control/workspaces)
2. 5 minutes en Python
Section intitulée « 2. 5 minutes en Python »pip install d2b-sdkfrom d2b import D2BClient
client = D2BClient(api_key="d2b_pat_...", base_url="https://d2b.dev")
# 1) A workbook is the working containerwb = client.workbooks.create(title="monthly-sales")["id"]
# 2) Throw the messy Excel at it. wait=True has the SDK babysit the 202+job.# After extraction and structuring you get clean, typed tablesresult = client.sources.upload(wb, "sales_2026-06.xlsx", wait=True)
# 3) See what landed (the basic agent move)for t in client.tables.list(wb): print(t["name"], t["row_count"])schema = client.tables.schema(wb, "sales")
# 4) Analyse with SQL (governance applied, read-only)out = client.query.sql(wb, 'SELECT product, sum(amount) FROM "sales" GROUP BY 1')
# 5) Derived tables are transforms (lineage is preserved)client.transforms.create( wb, name="agg/monthly", kind="sql", template='CREATE OR REPLACE TABLE "{{ artifact_name }}" AS ' 'SELECT product, sum(amount) AS revenue FROM "{{ src }}" GROUP BY 1', artifact_name="product_sales", args={"src": "sales"},)
# 6) Back to humansxlsx = client.export.tables(wb, tables=["product_sales"]) # formatted xlsxoriginal = client.sources.render_template(wb, "sales_2026-06.xlsx") # original formatting, values refreshed
# 7) Pin a versionclient.versions.commit(wb, "2026-06")3. La même chose avec curl
Section intitulée « 3. La même chose avec curl »BASE=https://d2b.dev; H="Authorization: Bearer $D2B_PAT"WB=$(curl -s -X POST $BASE/api/v1/workbooks -H "$H" -H "Content-Type: application/json" \ -d '{"title": "monthly"}' | jq -r .id)curl -s -X POST $BASE/api/v1/workbooks/$WB/sources -H "$H" -F file=@sales.xlsx -F mode=auto -F async=true# → {"job_id": ...} → poll GET $BASE/api/v1/jobs/{job_id}curl -s $BASE/api/v1/workbooks/$WB/tables -H "$H"curl -s -X POST $BASE/api/v1/workbooks/$WB/query -H "$H" -H "Content-Type: application/json" \ -d '{"sql": "SELECT count(*) FROM \"sales\""}'4. Avec la CLI
Section intitulée « 4. Avec la CLI »pipx install d2b-sdk # or uvx --from d2b-sdk d2b …d2b logind2b workbooks create --title monthlyd2b upload sales.xlsx --workbook WB --waitd2b query 'SELECT count(*) FROM "sales"' --workbook WBÉtapes suivantes : Concepts clés, Se connecter via MCP, Gérer les workbooks avec git.
Excel désordonné — quand auto, quand staged
Section intitulée « Excel désordonné — quand auto, quand staged »Commencez par le mode=auto par défaut (D2B découpe chaque feuille en ses tables et lit en-têtes fusionnés, lignes d’unités, lignes de sous-total et hiérarchie pour les mettre en forme). Ne passez à staged que si l’extraction ou la structuration a raté :
- Re-téléversez le même fichier avec
mode=staged(octets seuls, zéro interprétation) POST .../sources/{name}/analyze→ vérifiez et corrigez le parse spec renvoyé (ligne d’en-tête, plage de données, types)POST .../sources/{name}/materializepour valider
Le flux de décision : auto → examiner le résultat → en cas d’écart, reprendre la main sur le parse spec via staged. Le résultat auto reste sous son propre nom, ce qui permet de comparer en corrigeant.
Le champ structuring de la réponse d’upload annonce le résultat : structured, skipped (vous avez passé structuring=skip — les tables raw uniquement), deferred (vous avez passé structuring=defer — remplacées plus tard), raw_fallback (structuration demandée mais ce sont les tables raw qui sont revenues ; structuring_reason dit pourquoi — no_credits, building (ré-uploadez pour réessayer), failed:… — ou passez en staged) ou off (la structuration est désactivée sur ce serveur). La CLI affiche un avertissement sur stderr en cas de raw_fallback.
Les uploads via API / CLI / SDK / MCP sont structurés par D2B par défaut (structuring=auto) : chaque feuille est séparée en ses tables et les titres et notes qui les entourent (<feuille>_補足情報), et les tables découpées sont conservées telles qu’elles sont disposées sur la feuille. À partir de celles-ci, les tables avec des périodes en colonnes passent au format long, et les tables de rapport avec sous-totaux et totaux sont séparées en une table par niveau de leur hiérarchie (<table>_階層1, <table>_階層2 … ; les totaux et différences calculés à partir des lignes d’un même niveau vont dans <table>_階層1_計算項目, etc.) et leur arbre des comptes (<table>_科目). Une feuille qui n’est qu’une table sans rien autour n’est pas séparée, et sa table mise en forme prend le nom du fichier. La feuille d’origine reste dans la lignée. La structuration consomme les crédits du classeur (un nouvel upload du même contenu est servi depuis le cache, sans frais de structuration). Pour remodeler les tables raw avec votre propre LLM et add_transform, passez --no-structuring (API : structuring=skip) : chaque feuille est posée telle quelle, en ~1s et gratuitement. --defer-structuring (structuring=defer) renvoie les tables raw immédiatement, structure en arrière-plan et les remplace par les tables structurées une fois prêtes (artifact.updated est émis lors du remplacement).