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

# Authentication

> How to authenticate your BIZ MORI API requests

All API endpoints require an **API key** in the `Authorization: Bearer` header. Create and store the key in the [ContentCare Dashboard](https://app.contentcare.ai/keys); it is shown only once.

## Getting your API key

1. Sign in to the [ContentCare Dashboard](https://app.contentcare.ai)
2. Open [**API Keys**](https://app.contentcare.ai/keys)
3. Click **Issue New Key**
4. Copy and securely store the key — it is shown only once

> [!WARNING]
>
> Your API key grants access to your account. Keep it out of browser code, repositories, and version control.

## Test API keys

Use the automatically issued test API key with the `sk_test_` prefix when you need to verify an integration without running the underlying processing services. BIZ MORI issues one test key per account and organization, and you can retrieve it from the Dashboard API Keys page.

Test API keys:

* use the same `Authorization: Bearer` authentication as live keys;
* use the same order creation, upload, confirm, and query endpoints as live keys;
* do not run Anti-AI, watermark, or AI Detection processing;
* do not call external processing services or consume credits;
* keep test orders separate from live orders; and
* do not create downloadable result files.

For persistent test orders, the returned upload URL points to a BIZ MORI test upload route. The server consumes the request stream, records upload completion, and discards the file contents. Anti-AI upload mode and AI Detection still require a confirm call; Watermark Embed and Watermark Extract start after their uploads finish.

Test orders move through `pending`, `inProgress`, and `complete` or `failed` states. You can list, inspect, and aggregate your test orders with the normal order endpoints. A test download returns `404 PROCESSED_FILE_NOT_FOUND` because no result file is created. A test API key can manage only test webhook endpoints owned by the same owner; see [Test API keys](https://docs.contentcare.ai/test-api-keys.md) for the complete behavior and examples.

## Using your API key

Generate a UUIDv4 for each new logical order. The examples below create one before making the first Anti-AI order.

```bash cURL theme={null}
ORDER_IDEMPOTENCY_KEY=$(uuidgen | tr '[:upper:]' '[:lower:]')
curl -X POST https://api.bizmori.com/api/v2/orders/anti-ai \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"idempotencyKey\": \"$ORDER_IDEMPOTENCY_KEY\", \"files\": [{\"fileName\": \"image.jpg\"}]}"
```

```javascript Node.js theme={null}
import { randomUUID } from 'node:crypto';

const orderIdempotencyKey = randomUUID();
const response = await fetch('https://api.bizmori.com/api/v2/orders/anti-ai', {
  method: 'POST',
  headers: { Authorization: 'Bearer YOUR_API_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({ idempotencyKey: orderIdempotencyKey, files: [{ fileName: 'image.jpg' }] }),
});
const data = await response.json();
```

```python Python theme={null}
import uuid
import requests

order_idempotency_key = str(uuid.uuid4())
response = requests.post(
    'https://api.bizmori.com/api/v2/orders/anti-ai',
    headers={'Authorization': 'Bearer YOUR_API_TOKEN'},
    json={'idempotencyKey': order_idempotency_key, 'files': [{'fileName': 'image.jpg'}]},
)
data = response.json()
```

```php PHP theme={null}
<?php
$orderIdempotencyKey = sprintf('%04x%04x-%04x-4%03x-%x%03x-%04x%04x%04x', random_int(0, 0xffff), random_int(0, 0xffff), random_int(0, 0xffff), random_int(0, 0x0fff), random_int(8, 11), random_int(0, 0x0fff), random_int(0, 0xffff), random_int(0, 0xffff), random_int(0, 0xffff));
$ch = curl_init('https://api.bizmori.com/api/v2/orders/anti-ai');
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_TOKEN', 'Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode(['idempotencyKey' => $orderIdempotencyKey, 'files' => [['fileName' => 'image.jpg']]])]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```ruby Ruby theme={null}
require 'securerandom'
require 'net/http'
require 'json'
order_idempotency_key = SecureRandom.uuid
uri = URI('https://api.bizmori.com/api/v2/orders/anti-ai')
req = Net::HTTP::Post.new(uri, {'Authorization' => 'Bearer YOUR_API_TOKEN', 'Content-Type' => 'application/json'})
req.body = JSON.generate(idempotencyKey: order_idempotency_key, files: [{fileName: 'image.jpg'}])
data = JSON.parse(Net::HTTP.start(uri.host, uri.port, use_ssl: true) {|http| http.request(req) }.body)
```

```go Go theme={null}
package main

import (
	"bytes"
	"encoding/json"
	"net/http"

	"github.com/google/uuid"
)

func main() {
	orderIdempotencyKey := uuid.NewString()
	body, _ := json.Marshal(map[string]any{"idempotencyKey": orderIdempotencyKey, "files": []map[string]string{{"fileName": "image.jpg"}}})
	req, _ := http.NewRequest("POST", "https://api.bizmori.com/api/v2/orders/anti-ai", bytes.NewBuffer(body))
	req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
	req.Header.Set("Content-Type", "application/json")
	resp, _ := http.DefaultClient.Do(req)
	defer resp.Body.Close()
}
```

```java Java theme={null}
import java.net.URI;
import java.net.http.*;
import java.util.UUID;

public class Main {
  public static void main(String[] args) throws Exception {
    String orderIdempotencyKey = UUID.randomUUID().toString();
    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.bizmori.com/api/v2/orders/anti-ai"))
        .header("Authorization", "Bearer YOUR_API_TOKEN")
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(
            "{\"idempotencyKey\":\"" + orderIdempotencyKey + "\",\"files\":[{\"fileName\":\"image.jpg\"}]}"
        ))
        .build();
    HttpResponse<String> response =
        HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
  }
}
```

## Idempotency

Use a new UUIDv4 for every new logical order. Anti-AI and AI Detection confirms are separate logical requests, so generate a different UUIDv4 for each confirm. Reuse the previous value only when retrying the same logical request after a network failure. Sending the same key again returns the original order instead of creating a new one.

## Rate limits

All requests are subject to a global limit of 1,000 requests per 15 minutes and include standard `RateLimit` headers. Some endpoints may apply additional endpoint-specific limits.

For live order API keys, plan usage quota is separate from the global request limit. When that quota is exhausted and no active credit pack is available, the order API returns HTTP 429 with `{ "code": "PLAN_LIMIT_EXCEEDED" }`. Test API keys bypass the plan usage quota, but not the global request limiter, which runs before API-key authentication.

## Live and test API keys

With a live key, `uploadUrl` is an S3 presigned URL. With a test key, it is an absolute BIZ MORI API URL under `https://api.bizmori.com/api/v2/test-uploads/{signedToken}`. Both expire one hour after issuance; see [Quickstart](https://docs.contentcare.ai/quickstart.md) for upload and refresh behavior, and [Webhooks](https://docs.contentcare.ai/webhooks.md) for test-key webhook scope.


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