# decobuy CDK

> One CDK pays for one AI subscription. The buyer opens the activation page and enters their account id. decobuy is an independent reseller and is not affiliated with Anthropic.

Shop: https://cdk.decobuy.lol
API: https://cdk.decobuy.lol/api/cdk/v1
Activation page: https://activate.decobuy.lol/?code=<CODE>

There is no webhook. After redeem, read the CDK with POST /cdks/status until it settles.

## Rules that are easy to get wrong

- Money is a USD decimal string ("20.00"). Never a float, never cents.
- A CDK code looks like `DB-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX`. Send it as a JSON string.
- `product_id` comes from GET /products. It is a UUID string, not a price and not a Discord tier.
- Buying a CDK debits the balance immediately. Redeem does not charge again.
- Redeem needs `organization_id`: a UUID of 36 characters, the account id from the subscription settings. An email is rejected.
- One code can be redeemed once. Either your server calls redeem, or the buyer opens the activation page. Do not do both.
- CDK codes do not expire.
- The price in GET /products is the price POST /cdks will charge. It is not a third-party list price.
- This shop is not affiliated with Anthropic. Product names are the names of the subscriptions being activated.

## Auth

`X-API-Key: dbyyy_...` on every request. Create or revoke the key on the account page. Missing or revoked key: HTTP 401 `invalid_api_key`.

JSON over HTTPS. POST bodies are `Content-Type: application/json`.

Limits, counted per key:

- 20 requests per minute on this API.
- POST /cdks and POST /cdks/redeem each have an extra limit of 10 per minute.

HTTP 429 `rate_limited` includes a `Retry-After` header (seconds).

## Statuses

The response field `status` is one of:

- `active` — not redeemed. The buyer can still submit an account id.
- `processing` — redeemed, subscription not confirmed yet. Keep polling. You cannot tell internal steps apart, and you do not need to.
- `delivered` — the subscription was activated. There is no link to open.
- `invalid` — the CDK was cancelled. It cannot be used.

Once `status` is `processing` or `delivered`, the same code cannot be redeemed again.

`invalid` is not returned for an unknown code. Lookup, redeem and status of an unknown, cancelled, or someone else's code answer HTTP 404 `voucher_not_found`.

## Endpoints

Prefix `/api/cdk/v1`.

### GET /me

The account that owns the key.

- `username` — account name.
- `balance` — spendable USD. Purchases debit this.

```json
{"username": "shop1", "balance": "120.50"}
```

### GET /products

CDKs you can buy.

- `products[].id` — `product_id` for POST /cdks.
- `products[].name` — English product name.
- `products[].name_ru` — Russian name, or null.
- `products[].summary` — short text, may be empty.
- `products[].image_url` — picture for the shop card, or empty.
- `products[].price` — USD charged per CDK.

```json
{
  "products": [
    {
      "id": "6c9a1e4a-1c0b-4a3e-9f2d-7b8e5a1c0d11",
      "slug": "claude-pro",
      "name": "Claude Pro",
      "name_ru": "Claude Pro",
      "summary": "",
      "image_url": "/cdk/claude.png",
      "price": "20.00"
    }
  ]
}
```

### GET /stock

Whether activations can be fulfilled right now. This is not a list of unsold shop codes, and it does not return the codes.

- `products[].id` — same id as GET /products.
- `products[].name` — product name.
- `products[].in_stock` — true when at least one activation can still be fulfilled.
- `products[].available` — how many activations can still be fulfilled.

```json
{
  "products": [
    {"id": "6c9a1e4a-1c0b-4a3e-9f2d-7b8e5a1c0d11", "name": "Claude Pro", "in_stock": true, "available": 4}
  ]
}
```

### POST /cdks

Buy 1..100 CDKs of one product. HTTP 201. Debits `price` × `quantity`.

Path is `/api/cdk/v1/cdks`.

- `product_id` — required. Unknown or disabled: HTTP 404 `product_not_found`.
- `quantity` — required integer, 1..100.

- `total` — amount debited.
- `cdks[].code` — pass this to redeem and status.
- `cdks[].activation_url` — same CDK, as a link the buyer can open.

```json
{
  "total": "20.00",
  "cdks": [
    {"code": "DB-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX", "activation_url": "https://activate.decobuy.lol/?code=DB-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"}
  ]
}
```

### GET /cdks?page=1&size=50

CDKs bought by this key. `page` starts at 1. `size` is 1..100. The response has `total`, `page`, and `cdks`.
Each row is the same object POST /cdks/status returns.

### POST /cdks/lookup

One owned CDK, without starting activation. A code owned by another key is HTTP 404 `voucher_not_found`.

- `code` — required.

```json
{"code": "DB-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"}
```

```json
{
  "cdk": {
    "status": "active",
    "product_id": "6c9a1e4a-1c0b-4a3e-9f2d-7b8e5a1c0d11",
    "product_name": "Claude Pro",
    "price": "20.00",
    "organization_id": null
  }
}
```

### POST /cdks/redeem

Activate one CDK on an account. Does not charge again.

- `code` — required. Already redeemed: HTTP 409 `voucher_already_used`. Unknown: HTTP 404 `voucher_not_found`.
- `organization_id` — required UUID. Anything else: HTTP 400 `invalid_account` or HTTP 422 `validation_error`.

On success `status` is `processing` or `delivered`. There is no link in the response.

```json
{"cdk": {"status": "processing", "name": "Claude Pro"}}
```

HTTP 503 `delivery_unavailable` means this CDK cannot be activated right now. The code stays `active`.

### POST /cdks/status

Current state. Body: `{"code": "DB-..."}`.

```json
{"cdk": {"status": "delivered", "product_id": "6c9a1e4a-1c0b-4a3e-9f2d-7b8e5a1c0d11", "product_name": "Claude Pro", "price": "20.00", "organization_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"}}
```

Poll about every 5–10 seconds while `processing`. Faster polling does not finish the order sooner and can hit HTTP 429.

## Errors

```json
{"error": {"code": "delivery_unavailable", "message": "..."}}
```

- 401 `invalid_api_key` — missing or revoked key.
- 402 `insufficient_balance` — balance is below the total. No CDK is created.
- 404 `product_not_found` — product_id is unknown or disabled.
- 404 `voucher_not_found` — unknown, cancelled, or another account's code.
- 409 `voucher_already_used` — code is already redeemed.
- 400 `invalid_account` — organization id is not a UUID.
- 422 `validation_error` — body failed type, length, or range checks.
- 429 `rate_limited` — wait for `Retry-After`.
- 503 `delivery_unavailable` — cannot activate right now. The CDK stays `active`.
