Ir al contenido

Inicio rápido

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).

Ventana de terminal
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 requiere workbooks: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_id para apuntar a una de tus cuentas de desarrollador. GET /api/v1/me informa account_id / account_name
  • resource acota el alcance: workbook:<id> (solo ese workbook — la forma recomendada al entregar un token a un agente) o workspace:<id> (solo los workbooks de ese workspace; las creaciones también caen ahí). El valor por defecto account es todo lo que hay bajo la cuenta. El alcance lo fija solo resource; los scopes dicen qué puede hacer la clave — una clave sin workspaces:read sigue creando en cualquier workspace de su cuenta si está ligada a account. Indicar en workspace_id un workspace fuera del alcance devuelve 403 tanto al listar como al crear
  • GET /api/v1/me/workspaces lista los workspaces que alcanza el token, con nombre (is_default = dónde cae una creación si se omite workspace_id). /me y el listado de workbooks también traen workspace_name
  • La provisión de workspaces es workspaces:create, la emisión de claves keys:mint, las operaciones de facturación billing: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_id cae 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 clave workspaces:create (POST /api/control/workspaces)
Ventana de terminal
pip install d2b-sdk
from d2b import D2BClient
client = D2BClient(api_key="d2b_pat_...", base_url="https://d2b.dev")
# 1) A workbook is the working container
wb = 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 tables
result = 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 humans
xlsx = client.export.tables(wb, tables=["product_sales"]) # formatted xlsx
original = client.sources.render_template(wb, "sales_2026-06.xlsx") # original formatting, values refreshed
# 7) Pin a version
client.versions.commit(wb, "2026-06")
Ventana de terminal
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\""}'
Ventana de terminal
pipx install d2b-sdk # or uvx --from d2b-sdk d2b …
d2b login
d2b workbooks create --title monthly
d2b upload sales.xlsx --workbook WB --wait
d2b query 'SELECT count(*) FROM "sales"' --workbook WB

Siguiente: 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:

  1. Vuelve a subir el mismo archivo con mode=staged (solo bytes, cero interpretación)
  2. POST .../sources/{name}/analyze → revisa y corrige el parse spec devuelto (fila de cabecera, rango de datos, tipos)
  3. POST .../sources/{name}/materialize para 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).