Drive Endpoints

The Preview Drive API works with Google Drive, Microsoft 365, and Dropbox sources that a team manager has connected to a dashboard project. Every request needs a team API key, the relevant drive scope, and a current project grant. Read routes use api:drive:read; mutations use api:drive:write. Routes that target one connection or item also require an active selected source and the exact capability advertised by that connection; the connection collection uses the project-scoped connected-data collection decision instead of a synthetic list capability.

The drive family is controlled by the team's plan and may be disabled until it is enabled for that plan. Write access requires a manager to reauthorize the connection for changes. Write and read scopes are independent; a write-scoped token may perform the minimum target lookup needed for its mutation without receiving general read access.

Public resources

A drive connection exposes its numeric Chab connection_id, customer alias, provider label, selected source_type, safe state, and sorted public capabilities. It never exposes account, tenant, site, provider-drive, or credential identifiers.

A DriveItem has an opaque dri_... item ID that is valid only inside its project connection. It includes the connection ID, kind, customer-visible name, nullable parent ID and root-relative path, media metadata, opaque item and permission revisions, up to 20 owners, and current public actions. Provider IDs and version tags are never public.

List connections

GET /v1/drive/connections lists active drive connections for one project in case-insensitive alias order. A traversal uses a stable 15-minute snapshot, so renames and new connections appear on the next fresh traversal.

curl "https://www.chab.ai/v1/drive/connections?project_id=7&limit=50" \
  -H "Authorization: Bearer CHAB_API_KEY"

The response meta contains request_id, next_cursor, has_more, and limit. Pass an opaque cursor unchanged to fetch the next page.

List items

GET /v1/drive/items lists the selected root, or one folder when parent_id is supplied, in provider continuation order. limit defaults to 50 and accepts 1–100.

curl "https://www.chab.ai/v1/drive/items?project_id=7&connection_id=12&limit=50" \
  -H "Authorization: Bearer CHAB_API_KEY"

Item-list and search metadata adds coverage and structured warnings. Chab does not promise folders-first, alphabetical, or modified-time ordering.

POST /v1/drive/search performs a case-insensitive literal search against item names only. query is 1–500 Unicode characters. Provider query syntax and content, owner, MIME, date, or path filters are not accepted.

curl -X POST https://www.chab.ai/v1/drive/search \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id":7,"connection_id":12,"query":"quarterly report","limit":20}'

Search is a direct read and does not use idempotency.

Read item

GET /v1/drive/items/{item_id} refreshes protected item metadata from the provider and returns one DriveItem.

curl "https://www.chab.ai/v1/drive/items/dri_01JZ7H0A1B2C3D4E5F6G7H8J9K?project_id=7&connection_id=12" \
  -H "Authorization: Bearer CHAB_API_KEY"

An ID from another connection, an item outside the selected source, a shortcut to external content, a trashed item, and an externally deleted item all return not_found.

Download item

GET /v1/drive/items/{item_id}/download downloads a complete ordinary file. Ranges are not supported. Chab reauthorizes before delivery and returns either a safe short-lived redirect or a metered whole-object stream.

curl -L "https://www.chab.ai/v1/drive/items/dri_01JZ7H0A1B2C3D4E5F6G7H8J9K/download?project_id=7&connection_id=12" \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -o downloaded-file

Chab-streamed downloads are limited to 100 MiB and may incur egress credits even though the drive operation itself is non-billable. Redirected provider bytes do not pass through Chab. Do not send Range.

Export item

POST /v1/drive/items/{item_id}/export exports a provider-native document to pdf, text, html, or markdown when that exact format appears in the item's available_exports. The asynchronous result contains one protected artifact with role drive_export.

curl -X POST https://www.chab.ai/v1/drive/items/dri_01JZ7H0A1B2C3D4E5F6G7H8J9K/export \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: export-report-001" \
  -d '{"project_id":7,"connection_id":12,"output_format":"pdf"}'

Exports are limited to 100 MiB. Poll the returned operation, then download its artifact through the normal protected artifact endpoint.

Mutations

The following six endpoints return an asynchronous operation with HTTP 202. They require api:drive:write, the corresponding connection capability, and an Idempotency-Key for a live request. Poll the returned status_url and result_url. The operations are non-billable: they reserve no credits and do not consume a token credit budget. Paid-plan access, operation rate limits, concurrency limits, current project access, and connection health still apply. There is no drive operation quota window.

Use the current item available_actions and connection capabilities to discover support. A connector or item may support only a subset. Dropbox supports file replacement and file trash with revisions; it does not offer move or folder trash through this API. Unsupported actions return drive_item_action_unavailable or connection_capability_unavailable; Chab does not substitute another action.

All bodies are closed JSON objects. Upload and replacement accept one source: {"type":"file_id"|"artifact_id","id":"..."}. Files must have completed scanning and be available to this token in the target project. Reusable artifacts must be drive exports from the same project and token. Other downloadable artifacts are not automatically valid drive inputs. Raw multipart bodies, URLs, paths, and base64 content are not accepted here; upload bytes through the Files API first. Inputs may not exceed 100 MiB, and a lower source or connector limit also applies.

Accepted operations hold their source until they reach a terminal state. Expiry or requested deletion prevents new acceptance but waits for existing source holders before deleting bytes. Revoked project/token access and unsafe scan states still prevent further transfer. Source errors keep their shared codes: file_expired/artifact_expired (410), source_scan_pending (409), and source_scan_failed, source_quarantined, or source_too_large (422).

Names are trimmed, 1–255 characters, and cannot contain controls, /, \\, or be . or ... Microsoft connections also reject reserved system names, trailing dots/spaces, and "*:<>?|; Dropbox names are limited to 255 UTF-8 bytes. For creation, conflict_mode must be fail or create_copy. The latter tries the original name, then (copy), then (copy 2) through (copy 100) before the extension. Exhaustion returns resource_state_conflict. Replacement never uses a name collision as permission to overwrite a different item.

Add "dry_run":true to any mutation to validate without performing the change. It returns HTTP 200 with meta.dry_run=true, meta.live_requires_idempotency=true, and data.preview. No idempotency key is required, and supplying one does not reserve or replay it. Dry runs can read current metadata but do not read source bytes, reserve credits, consume a rate bucket/concurrency slot, create an operation or source hold, or modify the drive. New IDs, revisions, and mutation timestamps in the preview are null. Repeat validation at live execution: a preview does not lock the remote item.

Upload item

POST /v1/drive/items creates a file under parent_id, or at the selected root when it is null. It requires drive.items.upload.

curl -X POST https://www.chab.ai/v1/drive/items \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: upload-report-001" \
  -d '{"project_id":7,"connection_id":12,"parent_id":null,"source":{"type":"file_id","id":"fil_01JZ7H0A1B2C3D4E5F6G7H8J9K"},"name":"report.pdf","conflict_mode":"fail"}'

Replace item

PATCH /v1/drive/items/{item_id} replaces the exact file's bytes. It requires drive.items.update and the latest opaque expected_revision. A stale revision returns resource_revision_conflict. The Chab item ID stays stable; there is no public version-history or replacement-mode option.

curl -X PATCH https://www.chab.ai/v1/drive/items/dri_01JZ7H0A1B2C3D4E5F6G7H8J9K \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: replace-report-001" \
  -d '{"project_id":7,"connection_id":12,"source":{"type":"artifact_id","id":"art_01JZ7H0A1B2C3D4E5F6G7H8J9K"},"expected_revision":"opaque_revision"}'

Create folder

POST /v1/drive/folders requires drive.folders.create. Null parent_id selects the connection root. Creation conflict modes match file uploads.

curl -X POST https://www.chab.ai/v1/drive/folders \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: create-reports-001" \
  -d '{"project_id":7,"connection_id":12,"parent_id":null,"name":"Reports","conflict_mode":"fail"}'

Move item

POST /v1/drive/items/{item_id}/move requires drive.items.move, the latest expected_revision, and a target_parent_id in the same connection. Optional name renames the item during the move. The item ID stays stable. Destination collisions fail; moving into itself, a descendant, another root, or a shortcut is rejected. There is no copy-on-conflict mode.

curl -X POST https://www.chab.ai/v1/drive/items/dri_01JZ7H0A1B2C3D4E5F6G7H8J9K/move \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: move-report-001" \
  -d '{"project_id":7,"connection_id":12,"target_parent_id":"dri_01JZ7H0A1B2C3D4E5F6G7H8J9M","expected_revision":"opaque_revision"}'

Trash item

POST /v1/drive/items/{item_id}/trash requires drive.items.trash and the current expected_revision. It uses the connected drive's trash/recycle bin. It never falls back to permanent deletion. An already-trashed or externally deleted item returns not_found; Chab has no restore endpoint.

curl -X POST https://www.chab.ai/v1/drive/items/dri_01JZ7H0A1B2C3D4E5F6G7H8J9K/trash \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: trash-report-001" \
  -d '{"project_id":7,"connection_id":12,"expected_revision":"opaque_revision"}'

Permissions

POST /v1/drive/items/{item_id}/permissions requires drive.permissions.update and the latest expected_permission_revision. action is grant, update, or revoke; principal contains exactly type (user or group) and email. role is viewer, commenter, or editor for grant/update and must be omitted for revoke. Support depends on the connection and item. The current Microsoft connector supports update/revoke of existing direct permissions with a current item revision. New grants are unavailable. Google Drive and Dropbox permission mutations are unavailable; unsupported actions return drive_item_action_unavailable before a change.

Grant requires no existing direct match; update/revoke require exactly one direct match of normalized type and email. Missing, existing, or ambiguous matches return resource_state_conflict. Public links, domain sharing, ownership transfer, inherited permission changes, and notifications are not supported. A connector unable to perform the exact request without those effects rejects it.

curl -X POST https://www.chab.ai/v1/drive/items/dri_01JZ7H0A1B2C3D4E5F6G7H8J9K/permissions \
  -H "Authorization: Bearer CHAB_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: update-report-permission-001" \
  -d '{"project_id":7,"connection_id":12,"action":"update","principal":{"type":"user","email":"[email protected]"},"role":"viewer","expected_permission_revision":"opaque_permission_revision"}'

Mutation results and recovery

Successful results contain action, changed, item_id, nullable item, previous_revision, current_revision, trashed, and nullable permission. Permission outcomes contain the action, principal type/address, role, and new opaque permission revision. Item metadata uses the same DriveItem schema as reads. Provider IDs and session handles are never returned.

Use a fresh idempotency key for each intended change. Repeating a key, method, target, and identical body replays the accepted operation. A changed body in that slot conflicts; a different target has a separate slot. Retrying an ambiguous remote effect does not blindly repeat it. The operation waits for reconciliation and may time out if its outcome cannot be established. Removing access prevents subsequent protected effects; cancellation does not undo a change already applied. Each confirmed effect creates one content-free audit event; dry runs and replays do not duplicate it.

Errors

Drive endpoints use the shared error envelope. Important drive codes include:

Code Meaning
drive_item_action_unavailable The current provider item does not support the requested action.
drive_export_format_unavailable The format is not currently advertised for this item.
drive_item_too_large A Chab-served download exceeds 100 MiB.
drive_export_too_large Exported bytes exceed 100 MiB.
connection_access_removed Current project, connection, capability, or source access was removed.

Direct reads have a dedicated team/key/family/profile rate bucket and return RFC rate headers. Export uses operation rate and concurrency controls. See Errors, Rate Limits, and Pagination, Operations, and Operation Lifecycle.