# Moving a project to the Customnia Partner API

Step-by-step instructions for a developer or an AI coding agent that moves a project off the old design API
(`design.customnia.com/api`, also proxied at `designer.customnia.com/api`) onto the Partner API at
https://api.customnia.com/v1. Follow the steps in order; each one ends with a check.

Reference material, read before starting:

- https://api.customnia.com/docs — the guide, including the table "Moving from the old design API"
- https://api.customnia.com/docs/openapi.yaml — every endpoint, field and error (machine-readable)
- https://api.customnia.com/docs/changelog — what changed in which version

## Ground rules

- The API key is a server secret. Read it from the project's environment (`.env`, secrets store); never put it in
  browser JavaScript, a mobile app, a repository or a log line.
- Build and test with the test key (`cn_test_…`) first. Switch to the live key (`cn_live_…`) only for the cut-over
  and for `POST /designs/claim`, which a test key cannot call.
- Do not delete the old calls in the same change that adds the new ones: put the new client behind a switch (an
  env variable such as `CUSTOMNIA_API=partner|legacy`) so the project can go back in one step.
- Money is in US cents. The old API sent costs plus a store margin; the Partner API sends your wholesale price per
  color × size. Prices shown to buyers may change — check them with the project owner before the cut-over.
- Limits: 240 requests a minute per key (429 above that). The catalog changes rarely: cache `GET /catalog` for an
  hour instead of calling it on every page view.

## Step 1. Find every call to the old API

Search the whole project, including background jobs, cron scripts and front-end code:

```bash
grep -rnE "design\.customnia\.com|designer\.customnia\.com/api|api/blanks|customize-blanks" \
  --include='*.php' --include='*.js' --include='*.ts' --include='*.tsx' --include='*.vue' --include='*.py' \
  --include='*.env*' --include='*.json' --include='*.yaml' --include='*.yml' . | grep -v node_modules | grep -v vendor
```

Write the list down: file, line, old endpoint, what the project does with the answer.

Check: every line the search found is on the list, and each has its new endpoint from the table in Step 4.

## Step 2. Get keys and set up the client

Ask Customnia (hello@customnia.com) for a live key, a test key and, if the project wants order updates, a webhook
secret. Put them in the project's environment:

```
CUSTOMNIA_API_URL=https://api.customnia.com/v1
CUSTOMNIA_API_KEY=cn_live_…
CUSTOMNIA_API_TEST_KEY=cn_test_…
CUSTOMNIA_WEBHOOK_SECRET=…
```

Write one small client in the project (a class or module) that sends `Authorization: Bearer <key>` and
`Accept: application/json`, and turns 4xx answers into errors that keep the body's `error` and `message`.

Check: `GET /catalog` with the test key returns 200 and a `blanks` list.

```bash
curl -s https://api.customnia.com/v1/catalog -H "Authorization: Bearer $CUSTOMNIA_API_TEST_KEY" | head -c 400
```

## Step 3. Claim the designs the project already has

Designs made through the old API have no owner yet. Until the project claims them, the Partner API answers 404 for
them. Claiming keeps the design itself: the same record, the same `customized_blank_id` the project already stores,
the same print files.

1. Collect every old design id the project stores (the old API's `customize-blanks` `id`, often a column named
   like `customize_blank_id`, `customized_blank_id` or `design_id`).
2. Send them with the live key, at most 200 per request:

   ```bash
   curl -s https://api.customnia.com/v1/designs/claim -H "Authorization: Bearer $CUSTOMNIA_API_KEY" \
     -H "Content-Type: application/json" -d '{"customized_blank_ids": [172945, 172944]}'
   ```

3. Store the answer's `id` next to the old id: new calls take `id`; `customized_blank_id` stays as it was.
4. Look at `rejected`. `taken` means another partner has the design; `not_marked` means your key may not claim
   designs nothing marks as yours (ask Customnia); other errors say why in `message`. Do not retry
   rejected ids in a loop — send the list to Customnia.

Claiming is safe to repeat: an id the project already claimed comes back in `claimed` again. If storing the new id
is hard, `GET /designs?customized_blank_ids=1,2,3` finds claimed designs by their old ids.

Check: the number of claimed plus rejected equals the number of ids sent; `GET /designs/{id}` works for a few of
them and shows the same layers and print files the old API showed.

## Step 4. Replace each call

| Old call | New call |
|---|---|
| `GET\|POST /api/blanks`, `GET /api/blanks/filters` | `GET /catalog` with `category`, `brand`, `color`, `size`, `label`; the answer's `filters` lists their values |
| `GET /api/blanks/{id}` | `GET /catalog/{blank_id}` |
| `POST /api/blanks/{id}/customize-blanks` | `POST /designs` with `blank_id`, `color_id` (or `print_location_id`), `front_layers`, `back_layers`, `alternative`, `notes` at the top level |
| `GET /api/customize-blanks/{id}` | `GET /designs/{id}` |
| `POST /api/customize-blanks/list` | `GET /designs?customized_blank_ids=…` |
| `PUT /api/customize-blanks/{id}` | `PATCH /designs/{id}` (only the sides sent change; 409 `design_locked` once ordered) |
| `POST /api/customize-blanks/{id}/copy` | `POST /designs/{id}/copy` (the copy is a new design of yours) |
| `POST /api/customize-blanks/{id}/layers/copy` | `POST /designs/{id}/layers/copy` |
| `POST /api/customize-blanks/media/replace` | `POST /designs/media/replace` |
| `POST /api/customize-blanks/text/replace` | `POST /designs/text/replace` (answer `updated` instead of `changed`) |

Field changes that break code most often:

- A design's `id` is the new id; the old id is `customized_blank_id`.
- `front_artwork.fabric_layers` was a JSON string; `layers.front.canvas` is an object. Do not `JSON.parse` it.
- `blank_printing_location.color_model.dart` → `color.dark`; `blank_printing_location_id` → `print_location_id`.
- `front_artwork.platen_image` → `print_file_url` (also `print_files.front.main`); `preview_image` → `previews.front`.
- `sizes[].size` → `sizes[].name`; `colors[].dart` → `colors[].dark`; `brand_name` → `brand`.
- Costs and the store margin are gone: use `colors[].prices[size_id]` and `back_print_price` (cents).

The full field table is in the guide, section "Moving from the old design API".

Check: for every line from Step 1 the project now calls the new endpoint (behind the switch), and the project's own
tests pass.

## Step 5. Test with the test key

With the switch on `partner` and the test key:

- Load every page that shows the catalog; compare blanks, colors and sizes with the old answer.
- Create a design from layers, open it, change it, copy it to another blank and color.
- If the project replaces pictures or texts across designs, run that on test designs.
- If the project places orders through the Partner API: `POST /quotes`, `POST /orders`, then
  `POST /orders/{id}/simulate` with `printing`, `shipped`, `delivered` and check the webhooks arrive and verify.

A test key reads every design of the partner but changes only designs made with a test key, and orders placed with
it are never printed or charged.

Check: no request in the project's logs goes to `design.customnia.com` or `designer.customnia.com/api` while the
switch is on `partner`.

## Step 6. Cut over

1. Run Step 3 again with the live key for designs made since the first run.
2. Set the live key, switch to `partner`, deploy.
3. Watch the project's error log and the Partner API answers (4xx and 5xx) for a day.
4. Tell Customnia the project is moved, so its old-API traffic can be watched going to zero.

Remove the old client and the switch only after a week without falling back.

## When something is wrong

- 401: wrong or missing key, or a test key used where a live key is needed.
- 404 on a design: not claimed yet, or claimed by another partner (see Step 3).
- 409 `design_locked`: the design is in a placed order; copy it and change the copy.
- 422: the body's `errors` names each bad field.
- 429: more than 240 requests a minute; cache the catalog and retry later.

Questions and keys: hello@customnia.com.
