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

# Concepts

> Org scope, rate limits, idempotency, errors, and request tracing for the public API.

export const IdempotencyKeyGenerator = () => {
  const createKey = () => {
    if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
      return crypto.randomUUID();
    }
    return ('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx').replace(/[xy]/g, char => {
      const random = Math.random() * 16 | 0;
      const value = char === 'x' ? random : random & 0x3 | 0x8;
      return value.toString(16);
    });
  };
  const [key, setKey] = useState(createKey);
  const [copied, setCopied] = useState(false);
  const handleGenerate = () => {
    setKey(createKey());
    setCopied(false);
  };
  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(key);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch (_error) {
      setCopied(false);
    }
  };
  return <div className="not-prose my-4 rounded-xl border border-zinc-950/10 bg-zinc-50 p-4 dark:border-white/10 dark:bg-zinc-900/40">
      <p className="mb-1 text-sm font-medium text-zinc-950 dark:text-white">
        Test here — you can use this UUID
      </p>
      <p className="mb-3 text-sm text-zinc-950/70 dark:text-white/70">
        Copy it into the <code className="rounded bg-zinc-950/5 px-1 py-0.5 text-xs dark:bg-white/10">idem-key</code> header
        in Try it or curl. Generate a new value for every new player create.
      </p>
      <div className="flex flex-col gap-3 sm:flex-row sm:items-center">
        <code className="block min-w-0 flex-1 overflow-x-auto rounded-lg border border-zinc-950/10 bg-white px-3 py-2 font-mono text-sm text-zinc-950 dark:border-white/10 dark:bg-zinc-950 dark:text-white">
          {key}
        </code>
        <div className="flex shrink-0 gap-2">
          <button type="button" onClick={handleGenerate} className="rounded-lg border border-zinc-950/10 bg-white px-3 py-2 text-sm font-medium text-zinc-950 hover:bg-zinc-100 dark:border-white/10 dark:bg-zinc-950 dark:text-white dark:hover:bg-zinc-800">
            Generate
          </button>
          <button type="button" onClick={handleCopy} className="rounded-lg bg-teal-700 px-3 py-2 text-sm font-medium text-white hover:bg-teal-800 dark:bg-teal-600 dark:hover:bg-teal-500">
            {copied ? 'Copied' : 'Copy'}
          </button>
        </div>
      </div>
    </div>;
};

## Base URL and path

| Environment    | Example                                        |
| -------------- | ---------------------------------------------- |
| Sandbox        | `https://sandbox.blitzboardstats.com/api`      |
| Public routes  | `/v1/blitz-api/...`                            |
| Key management | Admin API `/api-keys` (Blitz super admin only) |

<Note>
  **Mintlify “Try it”:** playground requests are proxied through Mintlify (`api.playground.proxy: true`) so the browser does not hit sandbox CORS. Swagger at `https://sandbox.blitzboardstats.com/api/docs` calls the API same-origin and does not need that proxy.
</Note>

## Organization scope

* Keys are **org-scoped**, not “everything the user can see.”
* `GET/POST /v1/blitz-api/teams` always use the key’s organization.
* Any `teamId` must belong to that organization or the request is forbidden.

## Rate limiting

Public controllers are throttled at **100 requests / 60 seconds**. Exceeding the limit returns a throttle error; back off and retry.

## Idempotency key (`idem-key`)

An **idempotency key** is a client-generated string that uniquely identifies one create intent. The API stores it on the created player so the same write cannot be applied twice.

### Where it is required

Only **player create**:

```http theme={null}
POST /v1/blitz-api/teams/{teamId}/players
idem-key: 550e8400-e29b-41d4-a716-446655440000
```

| Header            | Required      | Notes                                                       |
| ----------------- | ------------- | ----------------------------------------------------------- |
| `idem-key`        | Preferred     | BlitzBoard header name                                      |
| `Idempotency-Key` | Also accepted | Same value; use if your HTTP client prefers the common name |

Missing either header → `400` (`idem-key is required in the header`).

### Generate a key

Use the generator below to create an `idem-key` you can paste into Try it or curl.

<IdempotencyKeyGenerator />

### What to send

* Any non-empty string that is **unique per create intent** (UUID recommended).
* Reuse the **same** key only when retrying the **same** create (network timeout, unclear response).
* Use a **new** key for every new player.

You can also generate offline:

```bash theme={null}
uuidgen
# or
node -e "console.log(crypto.randomUUID())"
```

### What happens on reuse

If a player was already created with that `idem-key`, a second request with the same key returns **`409 Conflict`** (`Idempotency key already used`) and does **not** create another player.

That protects against accidental duplicates. It does **not** replay the original success body — treat `409` as “this create already succeeded; look up the player or use a new key for a different player.”

## Request ID

Public routes attach a request id (middleware) for tracing. Include it when contacting support about a failed call.

## Errors

Errors follow the platform shape, for example:

```json theme={null}
{
  "error": 10014,
  "message": "organizationId should not be empty",
  "timestamp": "2026-09-13T14:45:41.317Z",
  "traceId": "req_41f0e6c8a5ea232a"
}
```

Common API-key messages:

| Message                                            | Meaning                                       |
| -------------------------------------------------- | --------------------------------------------- |
| API key is required                                | Missing `Authorization: Bearer ...`           |
| Invalid API key                                    | Wrong format, not `bb_live_`, or unknown hash |
| API key has been revoked                           | Key was revoked                               |
| API key has expired                                | Past `expiresAt`                              |
| Resource is outside the API key organization scope | Team/org mismatch                             |

## Permissions

After the API key is accepted, team-level role checks still apply for many player and schedule operations (same permission model as the main app). The acting user is the **organization creator** for the key’s organization (not the Blitz admin who issued the key).
