API overview
Authenticate with an API key and read your workspace over REST.
Basics
The BucketPilot API is a REST API over your workspace: buckets, objects, jobs, usage, and activity. Use a BucketPilot key instead of handling raw S3 credentials in your scripts — read your buckets, and (with a read/write key) upload, delete, copy, and manage objects. All requests and responses are JSON.
The base URL is https://bucketpilot.io/api/v1. API access is included on the Pro and Business plans.
Each key has a scope: a read key reaches every GET endpoint; a read/write key also reaches the endpoints that change something — object writes (upload, delete, copy, folders, tags, storage class), triggering a job run/pause/cancel, and reindexing. You pick the scope when you create the key.
Every endpoint at a glance:
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /v1/me | The key's workspace, plan, scope, and rate limit |
| GET | /v1/buckets · /v1/buckets/{id} | List / get buckets |
| GET | /v1/buckets/{id}/objects | Search indexed objects (paged) |
| GET | /v1/buckets/{id}/objects/metadata · /tags · /versions | Object metadata, tags, versions |
| POST | /v1/buckets/{id}/objects/download | Presigned download URL |
| POST | /v1/buckets/{id}/index | Start or resume indexing *(read/write)* |
| POST | /v1/buckets/{id}/objects/upload · /confirm | Presigned upload, then index it *(read/write)* |
| POST | /v1/buckets/{id}/objects/delete · /copy | Delete / copy-move objects *(read/write)* |
| POST | /v1/buckets/{id}/folders | Create a folder *(read/write)* |
| PUT | /v1/buckets/{id}/objects/tags · /storage-class | Set tags / storage class *(read/write)* |
| GET | /v1/jobs · /v1/jobs/{id} | List jobs / one job with its run log |
| POST | /v1/jobs/{id}/run · /pause · /cancel | Queue a run / stop a running job *(read/write)* |
| GET | /v1/usage · /v1/activity | Totals / newest activity events |
Quick start
- 1.Create a key under Settings → API keys and copy it — it's shown only once.
- 2.Confirm it works:
export BUCKETPILOT_KEY="bp_your_key_here"
curl https://bucketpilot.io/api/v1/me \
-H "Authorization: Bearer $BUCKETPILOT_KEY"- 1.List your buckets, then search one:
curl https://bucketpilot.io/api/v1/buckets \
-H "Authorization: Bearer $BUCKETPILOT_KEY"
curl "https://bucketpilot.io/api/v1/buckets/12/objects?search=*.csv" \
-H "Authorization: Bearer $BUCKETPILOT_KEY"From there: buckets & objects, jobs, and usage & activity.
Authentication
Create an API key under Settings → API keys. The full key is shown once at creation — store it somewhere safe; BucketPilot keeps only a hash. Keys are scoped to the workspace they were created in: personal keys need your own Pro (or Business) plan, while team-workspace keys follow the organization's Business plan and only admins can create or revoke them.
When you create a key you choose its permissions: Read-only (the default — list and download objects, read jobs and usage) or Read/write (also upload, delete, copy, and tag objects). Pick read-only unless the key needs to change data — a read/write key can delete and overwrite objects, so treat it as carefully as an S3 secret. The scope is fixed at creation; to change it, create a new key and revoke the old one.
Pass the key on every request as a bearer token:
curl https://bucketpilot.io/api/v1/me \
-H "Authorization: Bearer bp_your_key_here"GET /v1/me echoes back the key's workspace, plan, and rate limit — a good first call to confirm everything works. Revoking a key (Settings → API keys) disables it immediately.
{
"key": { "name": "ci-reporting", "prefix": "bp_1a2b3c4d", "createdAt": "2026-07-01T09:12:44.000Z" },
"workspace": { "type": "organization", "name": "Acme Inc" },
"plan": "business",
"rateLimit": { "requestsPerMinute": 300 }
}Rate limits
Limits are per key, per minute:
| Plan | Requests / minute |
|---|---|
| Pro | 60 |
| Business | 300 |
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (seconds until the window resets). Past the limit you get 429 with code RATE_LIMITED and a Retry-After header — back off and retry after that many seconds.
Errors
Errors are JSON: { "error": "human message", "code": "MACHINE_CODE" }. The code is stable — branch on it, not the message.
| Code | Status | Meaning — and the fix |
|---|---|---|
INVALID_API_KEY | 401 | Missing, malformed, unknown, or revoked key. |
API_PLAN_REQUIRED | 403 | The key's workspace no longer has a Pro or Business plan — keys disable on lapse and re-enable on upgrade. |
NOT_FOUND | 404 | No such resource in this key's workspace. |
NOT_INDEXED | 400 | Object search needs the bucket indexed first — POST /v1/buckets/{id}/index. |
ALREADY_RUNNING | 409 | The job is already mid-run. |
NOT_RUNNING | 409 | Pause/cancel on a job that isn't running. |
RATE_LIMITED | 429 | Over the per-minute limit; retry after Retry-After seconds. |
INDEX_LIMIT_REACHED | 403 | Indexing would exceed the plan's indexed-object allowance. |
BUCKET_UNLINKED | 409 | The bucket has no credential; relink it in the app first. |
LARGE_BUCKET | 409 | Too big for a direct scan — pass ?force=true or switch the bucket to inventory indexing in the app. |
READ_ONLY_KEY | 403 | A read-only key hit a write endpoint — create a read/write key. |
INVALID_KEY · INVALID_KEYS · INVALID_TAGS · INVALID_STORAGE_CLASS · INVALID_NAME | 400 | Malformed write request body. |
S3_ERROR | 502 | The underlying storage operation failed; safe to retry. |