퀵스타트
1. 인증 — PAT 발급하기
섹션 제목: “1. 인증 — PAT 발급하기”모든 /api/v1 호출은 PAT(Personal Access Token)의 Bearer 인증입니다. 콘솔에서 발급하거나, 로그인된 세션(JWT)으로 API에서 발급합니다.
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)- scope는 리소스×액션입니다:
workbooks:read/write/delete,cloud-files:read(Drive / OneDrive 목록·가져오기 — 로그인에는 기본 포함, PAT에는 명시),governance:configure,workspaces:read/create/configure/delete,keys:read/mint/revoke,account:read,billing:manage. 함의는 같은 리소스 안에서만(write ⊃ read). 워크북 삭제·snapshot restore·version revert에는workbooks:delete가 필요 - 토큰은 항상 정확히 하나의 계정에 고정됩니다(1 토큰 = 1 계정). 로그인 세션에서 발급하면 기본 계정 대상이며,
account_id로 자신의 개발자 계정을 지정할 수 있습니다.GET /api/v1/me가account_id/account_name을 반환합니다 resource로 범위를 좁힙니다:workbook:<id>(그 워크북만 — 에이전트에게 전달할 때 권장) 또는workspace:<id>(그 워크스페이스의 워크북만. 생성도 거기에 고정). 기본값account는 계정 아래 전부입니다. 도달 범위를 정하는 것은resource뿐이고 scope는 「무엇을 할 수 있는가」를 정합니다 —workspaces:read가 없는 키도account핀이면 계정 안의 어느 워크스페이스에든 만들 수 있습니다. 닿지 않는 워크스페이스를workspace_id에 지정하면 목록·생성 모두 403입니다GET /api/v1/me/workspaces로 토큰이 닿는 워크스페이스를 이름과 함께 확인할 수 있습니다(is_default=workspace_id생략 시 생성 위치)./me와 워크북 목록에도workspace_name이 붙습니다- 워크스페이스 프로비저닝은
workspaces:create, 키 발급은keys:mint, 결제 조작은billing:manage— 권한은 리소스×액션의 독립 scope이며 우산 scope는 없습니다. 필요한 권한만 조합해 발급하세요(GitHub fine-grained PAT와 같은 방식) workspace_id를 생략한 생성은 토큰 계정의 가장 오래된 워크스페이스(기본 계정이면 개인 워크스페이스)에 만들어집니다. 워크스페이스가 없는 개발자 계정은 409를 반환하므로, 먼저 콘솔(Workspaces)이나workspaces:create키(POST /api/control/workspaces)로 생성하세요
2. Python으로 5분
섹션 제목: “2. Python으로 5분”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. curl로 같은 작업
섹션 제목: “3. 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. CLI라면
섹션 제목: “4. 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다음: 핵심 개념, MCP로 연결하기, 워크북을 git으로 관리하기.
지저분한 Excel — 언제 auto, 언제 staged
섹션 제목: “지저분한 Excel — 언제 auto, 언제 staged”먼저 기본값 mode=auto 로 올립니다(D2B 가 시트를 표별로 잘라내고 병합 헤더·단위 행·소계 행·계층을 읽어 표를 정리합니다). 추출이나 구조화가 기대와 다를 때만 staged 로 내립니다:
- 같은 파일을
mode=staged로 다시 업로드(바이트 저장만, 해석 없음) POST .../sources/{name}/analyze→ 반환된 parse spec(헤더 행·데이터 범위·타입)을 확인·수정POST .../sources/{name}/materialize로 확정
판단 흐름: auto → 결과 확인 → 어긋나면 staged 로 parse spec 을 직접 제어. auto 결과는 별도 이름으로 남아 비교하며 고칠 수 있습니다.
업로드 응답의 structuring 필드가 결과를 명시합니다: structured(구조화 완료) / skipped(structuring=skip 지정 — 원본 표만) / deferred(structuring=defer 지정 — 나중에 교체) / raw_fallback(구조화를 요청했지만 원본 표 그대로. 이유는 structuring_reason 에 나옵니다 — no_credits 는 크레딧 부족, building 은 구축 중이라 재업로드로 재시도, failed:… 는 실패. staged 로 전환할 수도 있습니다) / off(이 서버에서 구조화가 꺼져 있음). CLI 는 raw_fallback 일 때 stderr 에 경고를 출력합니다.
API / CLI / SDK / MCP 를 통한 업로드도 기본적으로 D2B 가 구조화합니다(structuring=auto). 시트는 표와 그 주변의 제목·주석(<시트>_補足情報)으로 나뉘고, 잘라낸 표는 시트에 배치된 그대로 남습니다. 거기서 기간이 열로 늘어선 표는 세로형으로 정리되며, 소계·합계를 포함한 보고서 표는 계층별 표(<표>_階層1, <표>_階層2 …. 같은 계층의 행에서 계산되는 합계·차감은 <표>_階層1_計算項目 등)와 과목 트리(<표>_科目)로 나뉩니다. 주변에 아무것도 없는 표 하나뿐인 시트는 나누지 않고, 정리된 표가 파일 이름을 이어받습니다. 원본 시트는 계보에 남습니다. 구조화는 워크북의 크레딧을 소비합니다(같은 내용의 파일을 다시 업로드하면 캐시에서 반환되며 구조화 요금은 들지 않습니다). 원본 표 그대로 자신의 LLM 과 add_transform 으로 정형하고 싶다면 --no-structuring(API: structuring=skip)을 지정하면 시트를 있는 그대로 ~1초·무료로 착지시킵니다. --defer-structuring(structuring=defer)은 원본 표를 즉시 반환하고 구조화를 백그라운드에서 실행한 뒤 완료되면 구조화된 테이블로 교체합니다(교체 시 artifact.updated 이벤트 발생).