> ## Documentation Index
> Fetch the complete documentation index at: https://docs.everabyte.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Developer workflow

> A practical workflow for building, testing, and operating an Everabyte integration.

This page describes how teams usually build against the API. It focuses on decisions that affect reliability, not on product features.

## Separate human actions from automated actions

Everabyte deliberately splits responsibilities:

| Action | Where it happens | Why |
| - | - | - |
| Create and revoke API keys | Dashboard | Requires an authenticated human and step-up verification |
| Manage billing and plan | Dashboard | Payment and entitlement changes are human decisions |
| Create, update, delete buckets | Dashboard | Bucket lifecycle is a high-impact administrative action |
| Generate or rotate encryption keys | Dashboard / app | Required before uploads can succeed |
| Upload, download, organize files | REST API | Safe to automate with scoped keys |
| List buckets and read stored size | REST API | Read-only discovery inside the documented contract |
| Plan capacity and usage reporting | Dashboard | The API reports stored size, not the plan ceiling |

Do not design around an API-key route for key creation or bucket creation. Those routes are session-only and are rejected for API keys.

## Use one key per integration

Create a distinct key for each deployed service, and at least one for local development. A useful naming scheme is:

```text theme={null}
svc-invoicing-prod
svc-invoicing-staging
local-alice
```

This makes revocation precise. If a key leaks, you revoke one integration instead of rotating every credential in the company.

## Choose scopes before writing code

Start from the operations you actually need:

| Your integration does | Minimum useful scopes |
| - | - |
| Reads files and folder metadata | `buckets:read`, `files:read`, `folders:read` |
| Uploads and renames files | Read scopes plus `buckets:write`, `files:write` |
| Deletes files or folders | Write scopes plus `files:delete` or `folders:delete` |
| Copies or moves across buckets | `buckets:write` and the matching resource write scope |

Bucket scopes are the ceiling. A key with `files:write` but only `buckets:read` cannot perform writes. See [Scopes and permissions](https://docs.everabyte.com/authentication/scopes-and-permissions.md).

## Build for these realities

> **Uploads can fail after the connection starts**
>
> The server validates quota, plan limits, folder ownership, and encryption-key state while the multipart body is streaming. A rejection can arrive mid-upload. Your client must handle a non-2xx response even after it has sent bytes, and must not assume a file exists until it has a `fileId`.

> **Deletion has two modes**
>
> `trash=soft` moves a file to trash and keeps it restorable during the display window. `trash=hard` permanently deletes it. Retention and legal hold can block either mode. Model deletion as a state transition, not an immediate cleanup.

> **Retention is not a suggestion**
>
> An active retention policy makes a file immutable until it expires. Bucket-level retention can also block per-file changes and deletion. Read the retention state before offering destructive actions in your UI.

> **Rate limits are per key**
>
> The default limit is 600 requests per minute per key. The limiter is per key, not per endpoint. Batch work should be paced, and retries should use exponential backoff with jitter.

> **There is no documented sandbox host**
>
> This reference documents one production base URL. If you need isolated testing, use a separate company workspace and separate keys rather than assuming a sandbox domain exists.

## Handle responses consistently

Success and error envelopes are not identical:

```json theme={null}
{
  "status": 200,
  "message": "Buckets retrieved",
  "data": []
}
```

```json theme={null}
{
  "status": 403,
  "message": "This API key is restricted to specific buckets.",
  "data": null,
  "code": "API_BUCKET_SCOPE_DENIED"
}
```

Controller-level errors may use `error` instead of `code`:

```json theme={null}
{
  "status": 400,
  "message": "name: String must contain at least 1 character(s)",
  "error": null
}
```

Write one decoder that:

1. Checks `response.ok`.
2. Parses JSON only when the content type is JSON.
3. Reads `code` when present.
4. Falls back to `message` for display, never for branching.
5. Treats an unknown 5xx body as opaque.

See [Error handling](https://docs.everabyte.com/errors/overview.md).

## Treat downloads as streams

Files can be large. Do not buffer a download into memory just to save it. Stream to disk, a pipe, or your own object storage. Pass through `Range` when you need partial reads, and preserve the server's `Content-Range` and `206` status when you proxy the response.

## Observe your integration

At minimum, log:

* the HTTP method and route template, not the full URL with identifiers,
* the response status,
* the stable `code` when present,
* your own request ID,
* latency and bytes transferred.

Never log `X-Secret-Key`, full `X-Public-Key` values, file contents, or signed download URLs.

## Ship checklist

> [!TIP]
>
> Secrets live in a secret manager, not in source control.

> [!TIP]
>
> Each service has its own key with the narrowest scopes and bucket scope.

> [!TIP]
>
> Uploads handle mid-stream rejection and quota exhaustion.

> [!TIP]
>
> Deletes distinguish soft and hard behavior, and respect retention.

> [!TIP]
>
> Downloads stream and support resumption or range where needed.

> [!TIP]
>
> Retries use backoff and are idempotent at the application level.

> [!TIP]
>
> Error handling branches on HTTP status and stable `code`, not message text.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.