Inicio rápido
1. Autenticación — emitir el PAT
Sección titulada «1. Autenticación — emitir el PAT»Todas las llamadas a /api/v1 usan autenticación Bearer con un PAT (Personal Access Token). Emítelo desde la consola o desde la API con una sesión con login (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)- Los scopes son recurso×acción:
workbooks:read/write/delete,cloud-files:read(listar / importar desde Drive / OneDrive — activo por defecto en logins, explícito en PAT),governance:configure,workspaces:read/create/configure/delete,keys:read/mint/revoke,account:read,billing:manage. La implicación queda dentro de un recurso (write ⊃ read); borrar un workbook, restaurar un snapshot o revertir una versión requiereworkbooks:delete - Un token siempre está ligado a exactamente una cuenta (un token = una cuenta). Emitir desde una sesión iniciada apunta a tu cuenta predeterminada; pasa
account_idpara apuntar a una de tus cuentas de desarrollador.GET /api/v1/meinformaaccount_id/account_name resourceacota el alcance:workbook:<id>(solo ese workbook — la forma recomendada al entregar un token a un agente) oworkspace:<id>(solo los workbooks de ese workspace; las creaciones también caen ahí). El valor por defectoaccountes todo lo que hay bajo la cuenta. El alcance lo fija soloresource; los scopes dicen qué puede hacer la clave — una clave sinworkspaces:readsigue creando en cualquier workspace de su cuenta si está ligada aaccount. Indicar enworkspace_idun workspace fuera del alcance devuelve 403 tanto al listar como al crearGET /api/v1/me/workspaceslista los workspaces que alcanza el token, con nombre (is_default= dónde cae una creación si se omiteworkspace_id)./mey el listado de workbooks también traenworkspace_name- La provisión de workspaces es
workspaces:create, la emisión de claveskeys:mint, las operaciones de facturaciónbilling:manage— los permisos son scopes independientes recurso×acción sin scope paraguas; emite claves con exactamente lo que necesitan (estilo GitHub fine-grained PAT) - Una creación sin
workspace_idcae en el workspace más antiguo de la cuenta del token (el workspace personal en la cuenta predeterminada). Una cuenta de desarrollador sin workspace devuelve 409 — créalo antes en la consola (Workspaces) o con una claveworkspaces:create(POST /api/control/workspaces)
2. Python en 5 minutos
Sección titulada «2. Python en 5 minutos»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. Lo mismo con curl
Sección titulada «3. Lo mismo con 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. Con la CLI
Sección titulada «4. Con 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 WBSiguiente: Conceptos centrales, Conectar por MCP, Gestionar workbooks con git.
Excel desordenado — cuándo auto, cuándo staged
Sección titulada «Excel desordenado — cuándo auto, cuándo staged»Empieza con el mode=auto por defecto (D2B corta cada hoja en sus tablas y lee cabeceras combinadas, filas de unidades, filas de subtotal y la jerarquía para darles forma). Baja a staged solo cuando la extracción o la estructuración fallaron:
- Vuelve a subir el mismo archivo con
mode=staged(solo bytes, cero interpretación) POST .../sources/{name}/analyze→ revisa y corrige el parse spec devuelto (fila de cabecera, rango de datos, tipos)POST .../sources/{name}/materializepara confirmar
El flujo de decisión: auto → mirar el resultado → si falló, toma el control del parse spec vía staged. El resultado de auto queda con su propio nombre, así que puedes comparar mientras corriges.
El campo structuring de la respuesta indica el resultado: structured, skipped (pediste structuring=skip — solo las tablas raw), deferred (pediste structuring=defer — se intercambian después), raw_fallback (se pidió estructuración pero volvieron las tablas raw; structuring_reason dice por qué — no_credits, building (vuelve a subir para reintentar), failed:… — o pasa a staged) u off (la estructuración está desactivada en este servidor). La CLI imprime un aviso en stderr con raw_fallback.
Las subidas por API / CLI / SDK / MCP las estructura D2B por defecto (structuring=auto): cada hoja se divide en sus tablas y los títulos y notas que las rodean (<hoja>_補足情報), y las tablas cortadas se conservan tal como están dispuestas en la hoja. A partir de ellas, las tablas con periodos en las columnas se pasan a formato largo, y las tablas de informe con subtotales y totales se dividen en una tabla por nivel de su jerarquía (<tabla>_階層1, <tabla>_階層2 …; los totales y diferencias calculados a partir de filas del mismo nivel van a <tabla>_階層1_計算項目, etc.) y su árbol de cuentas (<tabla>_科目). Una hoja que es una sola tabla sin nada alrededor no se divide, y su tabla ya formada toma el nombre del archivo. La hoja original queda en el linaje. La estructuración consume los créditos del libro (subir de nuevo el mismo contenido se sirve desde la caché, sin cargo de estructuración). Para remodelar las tablas raw con tu propio LLM y add_transform, pasa --no-structuring (API: structuring=skip): cada hoja aterriza tal cual, en ~1s y gratis. --defer-structuring (structuring=defer) devuelve las tablas raw ahora, estructura en segundo plano e intercambia las tablas estructuradas cuando están listas (artifact.updated se dispara en el intercambio).