# CathyColor API integration guide (offline)

This guide is for existing customers managing API keys and making
server-side requests. New API sales and new customer provisioning are paused.
Existing customers can continue using the production API with active keys;
renewals and support continue. The production API is
`https://api.chinesecoloratlas.com` and covers 161 Chinese colors. It does not
provide a full color-catalog download, and browsers cannot call it directly
because CORS is not supported.

## Availability and usage

- New API sales and provisioning for new customer accounts are paused.
  Existing customer API access, active keys, renewals, and support continue.
- Existing accounts have 2,000 color-match inputs (one per RGB color) and
  1,000 text searches. The first quota period may be partial. Quotas reset on
  the first UTC day of the month, do not roll over, and stop at a hard limit.
  There are no automatic top-ups or overage charges.
- No service-level agreement is offered.

The commands below use a POSIX-compatible shell, such as Terminal on macOS or
Linux. Native Windows commands have not been verified. You need Node.js 20 or
later, `unzip`, and `curl`. The tool bundle has no third-party dependencies;
you do not need to run `npm install`.

## 1. Download and extract the tools

Download `key-delivery-tools.zip` from the online API integration guide. Save
the ZIP in Downloads, extract it to a private working folder, then run the
commands from that folder. If your browser saved the ZIP elsewhere, update its
path in the `unzip` command.

```sh
mkdir -p ~/cathycolor-api
unzip ~/Downloads/key-delivery-tools.zip -d ~/cathycolor-api
cd ~/cathycolor-api
node --version
```

Confirm that the Node.js version is 20 or later. The scripts are under
`tools/api-key-delivery/`. Keep your working folder outside your website's
public directory and source control.

## 2. Generate the public and private key files

For a key change supported for an existing account, the public JWK file lets
CathyColor encrypt an API key so only the matching private key can unlock it.
Share the public file only if support requests it; keep the private file on a
device you control. JWK is a JSON format for key files. The tool creates the
required 3072-bit RSA-OAEP (SHA-256) pair, writes both files with mode `0600`, and refuses to
overwrite existing files.

```sh
umask 077
node tools/api-key-delivery/generate-keypair.mjs \
  --public-out ./customer.public.jwk \
  --private-out ./customer.private.jwk
ls -l ./customer.public.jwk ./customer.private.jwk
```

Keep `customer.private.jwk` private. Never attach it to an email or send it to
support.

## 3. Existing-customer key support

New API sales and new customer provisioning are paused. Existing customers can
continue using their active keys, and renewals and support continue. For help
with an existing account, email [support@chinesecoloratlas.com](mailto:support@chinesecoloratlas.com)
from your account email. Share a public JWK only if support requests it for an
existing-account key change.

Suggested subject: `CathyColor API support`.

Do not attach `customer.private.jwk`, an API key, a full `Authorization`
header, or payment-card details. Do not paste either key into a public issue or
chat.

## 4. Read an encrypted key receipt

If support provides an encrypted receipt for an existing-account key change,
save it as `provisioning-receipt.json` in your private working folder. It
contains the API key as encrypted data, not readable plaintext. Keep the file
unchanged and private.

```sh
umask 077
node tools/api-key-delivery/decrypt-envelope.mjs \
  --envelope ./provisioning-receipt.json \
  --private-key ./customer.private.jwk \
  --key-out ./cathycolor.api-key \
  --purpose cathycolor_api_key_provisioning
```

The tool validates the receipt and writes the API key to
`cathycolor.api-key` with mode `0600`. It does not print the key and will not
overwrite an existing output file. Store the key in your secret manager. Do
not display it in a terminal recording or send it to support.

## 5. Verify the key once

Use only the active key issued to your account. This check reads `/v1/library`
without using quota and makes one `/v1/search` request, which uses one search
unit. Each additional run uses another search unit.

```sh
node tools/api-key-delivery/verify-key.mjs \
  --key-file ./cathycolor.api-key \
  --base-url https://api.chinesecoloratlas.com \
  --query red
```

Success reports HTTP `200` for both `library.status` and `search.status`. The
tool discards response bodies and prints status plus non-sensitive usage
metadata. If either status differs, keep the request details and contact
support without sending the key.

## 6. Make API calls

Run these examples from your backend environment. Turn off shell tracing while
the key is loaded; keep `API_KEY` local to this shell and do not export it.

```sh
set +x
API_BASE_URL="https://api.chinesecoloratlas.com"
API_KEY_FILE="./cathycolor.api-key"
API_KEY="$(tr -d '\n' < "$API_KEY_FILE")"
```

### Read library metadata — `GET /v1/library`

This quota-free endpoint returns release metadata, not color records.

```sh
curl --silent --show-error --include \
  --header "Authorization: Bearer $API_KEY" \
  "$API_BASE_URL/v1/library"
```

### Read current usage — `GET /v1/usage`

This quota-free endpoint returns both usage meters for the current UTC month.

```sh
curl --silent --show-error --include \
  --header "Authorization: Bearer $API_KEY" \
  "$API_BASE_URL/v1/usage"
```

### Match RGB colors — `POST /v1/match`

Send 1–5 RGB colors. Each input color uses one match unit; optional `top` must
be 1–3. A new logical request needs its own idempotency key.

```sh
MATCH_IDEMPOTENCY_KEY="match-$(node -e 'process.stdout.write(require("node:crypto").randomUUID())')"

curl --silent --show-error --include \
  --header "Authorization: Bearer $API_KEY" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: $MATCH_IDEMPOTENCY_KEY" \
  --data '{"colors":[{"r":12,"g":34,"b":56}],"top":2}' \
  "$API_BASE_URL/v1/match"
```

### Search color names — `GET /v1/search`

Each search uses one search unit. After trimming, `q` must be 2–64 characters;
`limit` cannot exceed 10.

```sh
SEARCH_IDEMPOTENCY_KEY="search-$(node -e 'process.stdout.write(require("node:crypto").randomUUID())')"

curl --silent --show-error --include \
  --header "Authorization: Bearer $API_KEY" \
  --header "Idempotency-Key: $SEARCH_IDEMPOTENCY_KEY" \
  "$API_BASE_URL/v1/search?q=black&limit=3"

unset API_KEY
```

The API returns bounded, minimal color records. There is no customer endpoint
that lists or downloads the full catalog.

## 7. Retry metered requests safely

`POST /v1/match` and `GET /v1/search` require an `Idempotency-Key` with 8–128
ASCII letters, digits, `.`, `_`, `:`, or `-` characters. Generate one key per
new logical request. After a timeout, a 5xx response, or `409
request_in_progress`, retry the exact same request with the same key. A
successful replay does not charge the operation again. Reusing a key with
different request data returns `409 idempotency_conflict`; use a new key only
for a genuinely new request.

Every response includes `X-Request-Id`. Keep it with the non-secret request
details in case you need support.

## 8. Understand common errors

| Status | Meaning and action |
| --- | --- |
| `400` | A metered request is missing a valid `Idempotency-Key`; add one. |
| `401` | The API key is missing, invalid, revoked, or expired. Check your secret file and `Authorization` header. Never send the key to support. |
| `403` | `account_unavailable`: stop retrying and contact support with the request ID and error details. |
| `409` | `idempotency_conflict`: the key was reused for a different request. `request_in_progress`: retry the exact request with the same key. |
| `422` | Fix invalid input, such as an RGB channel outside 0–255, a match batch outside 1–5, or a search query outside 2–64 characters. |
| `429` | `rate_limited` is an abuse-protection limit; honor `Retry-After` (normally 60 seconds). `quota_exceeded` means a monthly hard limit is used; honor its retry hint (normally 86,400 seconds), but that hint does not mean the monthly quota resets then. Only quota errors include usage headers. |
| `500` or `503` | If a metered request has an uncertain result, retry the exact request with the same idempotency key and back off between attempts. |

Do not retry in parallel or use extra requests to bypass a rate or quota limit.

## 9. Key safety and support

- Keep the private JWK, encrypted receipt, and API key in private storage. Do
  not put them in source control, tickets, chat, shell history, CI logs, or
  terminal recordings.
- If you need a planned key rotation, contact support from your subscription
  email and attach only a newly generated public JWK. Use the rotation purpose
  `cathycolor_api_key_rotation` when decrypting the rotation receipt.
- If you suspect a key has been exposed, stop using it and contact support.
  Do not include the private JWK, API key, or full authorization header.
- For a support request, provide the subscription email, endpoint path, UTC
  time, HTTP status, error code, and `X-Request-Id`. Do not send a request
  body, RGB values, search terms, or credentials.

Support email: [support@chinesecoloratlas.com](mailto:support@chinesecoloratlas.com)

## 10. Data and attribution

Only the current 161-color commercial set is available through the API.
`/v1/library` returns release metadata only; match and search return bounded
results, not a complete color-record list. Do not use the API to reconstruct,
scrape, mirror, or redistribute the full color catalog. Preserve the CathyColor
/ Chinese Color Atlas and upstream MIT attribution provided with the release
or contract when displaying or deriving from returned colors.

The `reliability` field describes sourcing confidence (`verified`,
`attributed`, or `disputed`); it does not mean every modern HEX value is an
official historical standard.
