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

# Report key usage

> Send the usage of the API keys that your gate issues at account creation, so that a shared or stolen key increases the risk of its account.

If your product gives each new account an API key, account creation is only half of the story. People can sell a key again, share it in a group chat or leak it in a public repository. Such a key then gets requests from many places at once. Report the usage of your issued keys. NoResponse then links that usage back to the account that got the key.

## How it fits together

**1. Send the hash of the key**

When your gate issues a key at account creation, send its SHA-256 as `issued_credential.sha256` on the assessment. Each SDK has a helper that calculates it: `hashIssuedCredential` in Node, `hash_issued_credential` in Python. The key itself does not leave your backend.

**2. Record each request in your gateway**

In your API gateway, record every request that uses an issued key. Record the key and the client IP. If you have them, also record the user agent, the model and the token counts. The SDK buffer hashes the key, puts the facts in batches, and sends them to `POST /v1/key_usage/batches` in the background.

**3. Read the reason on the account**

A key can get requests from 20 or more IP addresses, or from 3 or more countries, within 24 hours. Then every account whose assessment carried that key gets the `shared_api_key` reason (weight 30) in its current risk. You read it on `GET /v1/accounts/{account_id}`, and in the `account` of every assessment of that account.

The reason stays for 30 days after the last batch that found the key over the limit. This applies only while NoResponse keeps the assessment that carried the key. An assessment that you deleted, or that is past your retention, does not link the key to its account.

`shared_api_key` belongs to the account, so it changes `account.risk` and the decision for the account. The `detail.risk` of an assessment does not carry it. NoResponse counts IPv6 addresses by their `/64`. Thus the rotating addresses of one device count once.

## Buffer usage in your gateway

Make one buffer for each process, with a key that has the `assess` scope. Record each request, and close the buffer on shutdown. `record` does not block and does not throw, so it is safe on your request path.

```ts title="TypeScript" theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
const usage = nr.keyUsage.buffer(); // sends every 5 s, or once 100 facts are queued

// Once per request made with an issued key.
function onRequest(issuedKey: string, ip: string, userAgent: string | undefined): void {
  usage.record({ key: issuedKey, ip, userAgent, model: "gpt-4o-mini", inputTokens: 812, outputTokens: 164 });
}

// On shutdown, send what is queued.
await usage.close();
```

```python title="Python" theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
usage = client.key_usage.buffer()  # sends every 5 s, or once 100 facts are queued


# Once per request made with an issued key.
def on_request(issued_key: str, ip: str, user_agent: str | None) -> None:
    usage.record(key=issued_key, ip=ip, user_agent=user_agent, model="gpt-4o-mini", input_tokens=812, output_tokens=164)


# On shutdown, send what is queued. The buffer also sends it when the interpreter exits.
usage.close()
```

If you pass `key`, the SDK hashes it in your process. If you already store the hash, pass `keySha256` (`key_sha256` in Python).

The buffer sends a batch in two cases:

* When the queue holds `batchSize` facts (default 100, at most 500).
* At each `flushIntervalMs` (default 5,000 ms). In Python it is `flush_interval`, in seconds.

The buffer holds at most `maxQueue` facts (default 10,000). When the queue is full, the buffer drops the oldest fact and counts it. Thus a slow network costs you old facts, not memory. `stats()` gives the number of facts that are queued, sent, dropped, failed and refused.

Each batch carries its own `Idempotency-Key`. The SDK sends the same key on every retry of that batch. Thus NoResponse counts once a batch that the SDK retried after a lost answer. If a batch still fails after the retries, the SDK counts it in `failed` and passes it to `onError` (`on_error`).

The other SDKs give the route as a method that sends one batch: `KeyUsage.Record` in Go, `keyUsage().record` in Java, `KeyUsage.RecordAsync` in C#, `keyUsage->record` in PHP and `key_usage.record` in Ruby. Put the events in batches yourself, at most 500 for each call.

## Sampling

If your gateway serves more requests than you want to report, record a part of them. Set `sampleRate` (`sample_rate`) to a value above 0 and at most 1, such as `0.1`. The buffer records that part of the facts at random, and sends the rate with each event. Thus the request and token totals stay correct. The counts of distinct IPs and countries see only the events that you send. Thus with a low rate, a shared key shows up later.

## What NoResponse keeps

NoResponse keeps no raw event.

| Fact | Kept as | For |
| - | - | - |
| The key | Its SHA-256, which you send | As long as the usage totals |
| Requests, input tokens and output tokens | A total for each key | 30 days after the last use of the key, or your retention if that is shorter |
| The IP address | A keyed digest and its country | 24 hours |
| The user agent and the model | A keyed digest | 24 hours |

Each organisation has its own digest key. Thus the same IP in two organisations gives two unrelated digests. Some events add nothing, and the `ignored` count of the answer includes them:

* An event whose IP is private, reserved or unreadable.
* An event whose time is more than 24 hours old, or more than 5 minutes in the future.

> [!NOTE]
>
> NoResponse also counts a key that no assessment carried. When an assessment carries its hash in `issued_credential.sha256`, the usage applies to the account of that assessment.

The request and its limits are in [Report key usage](https://docs.noresponse.org/reference/key-usage.md).


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