Pular para o conteúdo

Quickstart

Toda chamada a /api/v1 usa autenticação Bearer com um PAT (Personal Access Token). Emita um no console ou pela API, a partir de uma sessão autenticada (JWT).

Terminal window
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)
  • Os scopes são recurso×ação: workbooks:read/write/delete, cloud-files:read (listar / importar do Drive / OneDrive — padrão em logins, explícito em PATs), governance:configure, workspaces:read/create/configure/delete, keys:read/mint/revoke, account:read, billing:manage. A implicação fica dentro de um recurso (write ⊃ read); excluir um workbook, restaurar um snapshot ou reverter uma versão requer workbooks:delete
  • Um token está sempre vinculado a exatamente uma conta (um token = uma conta). Emitir a partir de uma sessão autenticada aponta para sua conta padrão; passe account_id para apontar para uma de suas contas de desenvolvedor. GET /api/v1/me informa account_id / account_name
  • resource restringe o alcance: workbook:<id> (só esse workbook — a forma recomendada ao entregar um token a um agente) ou workspace:<id> (só os workbooks desse workspace; criações também caem lá). O padrão account é tudo sob a conta. O alcance é definido só por resource; os scopes dizem o que a chave pode fazer — uma chave sem workspaces:read ainda cria em qualquer workspace da sua conta quando fixada em account. Indicar em workspace_id um workspace fora do alcance devolve 403 tanto ao listar quanto ao criar
  • GET /api/v1/me/workspaces lista os workspaces que o token alcança, por nome (is_default = onde uma criação cai quando workspace_id é omitido). /me e a listagem de workbooks também trazem workspace_name
  • O provisionamento de workspaces é workspaces:create, a emissão de chaves keys:mint, as operações de faturamento billing:manage — as permissões são scopes independentes recurso×ação, sem scope guarda-chuva; emita chaves com exatamente o que precisam (estilo GitHub fine-grained PAT)
  • Uma criação sem workspace_id cai no workspace mais antigo da conta do token (o workspace pessoal na conta padrão). Uma conta de desenvolvedor sem workspace retorna 409 — crie um antes no console (Workspaces) ou com uma chave workspaces:create (POST /api/control/workspaces)
Terminal window
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")
Terminal window
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\""}'
Terminal window
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

A seguir: Conceitos centrais, Conectar via MCP, Gerenciar workbooks com git.

Comece com o mode=auto padrão (o D2B corta cada planilha em suas tabelas e lê cabeçalhos mesclados, linhas de unidade, linhas de subtotal e a hierarquia para dar forma a elas). Desça para staged só quando a extração ou a estruturação errou:

  1. Reenvie o mesmo arquivo com mode=staged (só bytes, zero interpretação)
  2. POST .../sources/{name}/analyze → revise e corrija o parse spec devolvido (linha de cabeçalho, faixa de dados, tipos)
  3. POST .../sources/{name}/materialize para confirmar

O fluxo de decisão: auto → olhar o resultado → se errou, assuma o parse spec via staged. O resultado do auto fica com nome próprio, então dá para comparar enquanto corrige.

O campo structuring da resposta de upload declara o resultado: structured, skipped (você passou structuring=skip — só as tabelas raw), deferred (você passou structuring=defer — trocadas depois), raw_fallback (a estruturação foi pedida mas voltaram as tabelas raw; structuring_reason diz por quê — no_credits, building (reenvie para tentar de novo), failed:… — ou passe para staged) ou off (a estruturação está desativada neste servidor). A CLI imprime um aviso em stderr com raw_fallback.

Uploads via API / CLI / SDK / MCP são estruturados pelo D2B por padrão (structuring=auto): cada planilha é dividida em suas tabelas e nos títulos e notas ao redor delas (<planilha>_補足情報), e as tabelas cortadas ficam como estão dispostas na planilha. A partir delas, tabelas com períodos nas colunas passam para o formato longo, e tabelas de relatório com subtotais e totais são divididas em uma tabela por nível da sua hierarquia (<tabela>_階層1, <tabela>_階層2 …; totais e diferenças calculados a partir de linhas do mesmo nível vão para <tabela>_階層1_計算項目 etc.) e na sua árvore de contas (<tabela>_科目). Uma planilha que é uma única tabela sem nada ao redor não é dividida, e sua tabela formatada assume o nome do arquivo. A planilha original fica na linhagem. A estruturação consome os créditos da pasta de trabalho (enviar de novo o mesmo conteúdo é servido do cache, sem custo de estruturação). Para remodelar as tabelas raw com seu próprio LLM e add_transform, passe --no-structuring (API: structuring=skip): cada planilha aterrissa como está, em ~1s e de graça. --defer-structuring (structuring=defer) devolve as tabelas raw agora, estrutura em segundo plano e troca pelas tabelas estruturadas quando prontas (artifact.updated dispara na troca).