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

# API conventions

> Format, pagination, errors, rate limits, auditing, and versioning for the Compliance API

The base URL is `https://app.base44.com/api/v1/compliance`. Every path in this reference is relative to it and begins with the workspace ID.

## Format

* Responses are JSON, UTF-8.
* Timestamps are ISO 8601 UTC with an explicit designator, such as `"2026-07-01T12:34:56Z"`. Fields that were never set are `null`.
* Every object has a stable string `id`. Where a natural ID doesn't exist, a deterministic composite is used. An entity is `{app_id}:{entity_name}`, for example, which is stable across scans and safe to deduplicate on.
* A `null` value means "not configurable" or "unknown", never "off". Reporting a control that doesn't exist as `false` would surface in your report as a finding that doesn't exist.
* Consumers must ignore unknown fields and unknown enum values. Evolution within `/v1` is additive only.

## Pagination

All list endpoints use opaque cursor pagination.

```json theme={null}
{
  "data": [ ... ],
  "pagination": {
    "total": 1234,
    "next_cursor": "opaque-string-or-null",
    "has_more": true
  }
}
```

* `limit` accepts 1 to 1000, and defaults to 100.
* Pass `next_cursor` back unchanged as `?cursor=...`. Cursors are valid for 24 hours.
* Don't re-send `limit` or a filter alongside a cursor, and don't present a cursor against another workspace. Both return `400` rather than silently resuming somewhere unintended.
* Paging is keyset-based, so rows written mid-scan don't shift the window under you.
* `total` is exact on the first page. Later pages may carry the same cached value.

## Errors

```json theme={null}
{
  "error": {
    "type": "permission_error",
    "message": "human-readable detail",
    "code": "missing_scope",
    "required_scope": "compliance:members:read"
  }
}
```

The `type` field is the contract. The `message` field is human-readable and may change. The `code` field narrows the cause where one is known, and `required_scope` accompanies `missing_scope`.

| HTTP | `type` | `code` | Retry? |
| - | - | - | - |
| 400 | `invalid_request_error` | None | No. Fix the request. Also returned for an invalid or expired cursor. |
| 401 | `authentication_error` | None | No. The workspace API key is missing, unknown, or disabled. |
| 401 | `authentication_error` | `partner_key_required` | No. Your assertion is missing or unverifiable. The customer's key isn't at fault, so don't ask them to re-mint one. |
| 402 | `permission_error` | `plan_not_included` | No. The plan doesn't include the API, or the subscription has lapsed. |
| 403 | `permission_error` | `missing_scope` | No. The customer didn't grant this family. |
| 403 | `permission_error` | `workspace_mismatch` | No. The key belongs to another workspace. |
| 403 | `permission_error` | `feature_not_enabled` | No. It isn't yet switched on for this workspace. Contact Base44. |
| 403 | `permission_error` | `partner_not_approved` | No. Your registration is suspended. Contact Base44, because the customer can't grant this. |
| 404 | `not_found_error` | None | No. |
| 429 | `rate_limit_error` | None | Yes. Honor `retry-after`, and don't advance cursors. |
| 500 | `api_error` | None | Yes. Use exponential backoff, with a freshly signed token. |
| 500 | `api_error` | `inventory_too_large` | No. This is a permanent limit. Contact Base44. |

You never receive a `422`. Validation failures arrive as a `400` in this envelope.

## Rate limits

Each workspace has a request budget, shared by every key in that workspace and every partner calling it. The baseline is 100 requests per 60 seconds, multiplied for Enterprise workspaces. At the current Enterprise multiplier the limit is 1,000 requests per 60 seconds, and a workspace may carry a custom multiplier instead. At 1,000 items per page, a 10,000-app workspace inventories in a handful of requests per endpoint.

A `429` carries `retry-after` in seconds and doesn't spend your token, because the limit is applied before the assertion is consumed. Sign a fresh token for every retry regardless. A request that reaches the handler spends its token even if the handler then fails, so replaying the same assertion after a `500` returns `401`.

## Auditability

Every read is recorded in the customer's own audit log as `workspace.compliance_api.read`. Customers see every scan you run, and a leaked key is investigable.

Granularity is one record per key, per partner, per endpoint, per outcome, per hour. That's at most two records an hour for a given endpoint, one success and one failure. Read the log as a record that reads happened, not as a count of them. A record can also be lost if the audit path itself is failing, and the hourly window means it isn't retried until the window turns over.

Each record names the key by an `actor_id` matching the `id` in [API keys](https://docs.base44.com/developers/references/compliance-api/get-started/keys-data-and-functions.md), and names you by your registered slug. Your attribution is cryptographic, because you proved the call with a signature only you can produce.

## Versioning

The version lives in the mount path, `/api/v1/`. Within v1, changes are additive only, with field renames handled by deprecation in place. Old and new fields coexist through a notice period. Breaking changes get 30 days' notice while the API is in beta and six months once it's generally available, along with a migration guide.


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