Quickstart
1. Autenticação — emita um PAT
Seção intitulada “1. Autenticação — emita um PAT”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).
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 requerworkbooks: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_idpara apontar para uma de suas contas de desenvolvedor.GET /api/v1/meinformaaccount_id/account_name resourcerestringe o alcance:workbook:<id>(só esse workbook — a forma recomendada ao entregar um token a um agente) ouworkspace:<id>(só os workbooks desse workspace; criações também caem lá). O padrãoaccounté tudo sob a conta. O alcance é definido só porresource; os scopes dizem o que a chave pode fazer — uma chave semworkspaces:readainda cria em qualquer workspace da sua conta quando fixada emaccount. Indicar emworkspace_idum workspace fora do alcance devolve 403 tanto ao listar quanto ao criarGET /api/v1/me/workspaceslista os workspaces que o token alcança, por nome (is_default= onde uma criação cai quandoworkspace_idé omitido)./mee a listagem de workbooks também trazemworkspace_name- O provisionamento de workspaces é
workspaces:create, a emissão de chaveskeys:mint, as operações de faturamentobilling: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_idcai 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 chaveworkspaces:create(POST /api/control/workspaces)
2. Python em 5 minutos
Seção intitulada “2. Python em 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. O mesmo com curl
Seção intitulada “3. O mesmo com 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. Ou com a CLI
Seção intitulada “4. Ou com a 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 WBA seguir: Conceitos centrais, Conectar via MCP, Gerenciar workbooks com git.
Excel bagunçado — quando auto, quando staged
Seção intitulada “Excel bagunçado — quando auto, quando staged”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:
- Reenvie o mesmo arquivo com
mode=staged(só bytes, zero interpretação) POST .../sources/{name}/analyze→ revise e corrija o parse spec devolvido (linha de cabeçalho, faixa de dados, tipos)POST .../sources/{name}/materializepara 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).