Invoking the agent
Claude Code is the reference implementation. From your integration repo:Prime directives
- Never silently drop functionality. Anything without a 1-to-1 v2 mapping gets a flag in
MIGRATION_GAPS.mdand aTODO(zinc-migration)comment at the call site. - Commit per phase. Each numbered phase below is a separate commit, so the human can review small diffs.
- Surface uncertainty. If you can’t tell whether a string is a product ID or a URL, whether
max_priceis in cents or dollars, whether a status branch should map toorder_placedorin_progress— flag it instead of guessing. - Do not invent credentials or secrets. API keys, webhook secrets, retailer credentials, and the v2 base URL come from the human via env vars or the dashboard.
- The live docs are the source of truth. Where this runbook and the live docs disagree, the live docs win — v2 evolves and your training data may be stale.
Webhook Wire Reference
v2 delivers all events to a single webhook URL configured per account in the dashboard. The agent must not invent this URL, the secret, or the header names — they are fixed by the API and reproduced here so Phase 6 does not depend on fetching live docs.Delivery
- Transport: HTTP
POSTto the account’s configuredwebhook_url. Content-Type: application/json- Headers on every delivery:
X-Webhook-Event— the event name (e.g.order.failed)X-Webhook-Signature— hex-encoded HMAC-SHA256 of the raw request body
Signature verification
The signature isHMAC-SHA256(secret, raw_body), hex-encoded. The secret is the
account’s webhook signing secret (prefix zn_whsec_), obtained from the
dashboard — never generated by the agent. Compute the HMAC over the exact bytes
received, before any JSON re-serialization, and compare timing-safely.
Payload envelope
return_idis populated only onreturn.*events; it isnullfor order events.statusis the order status fororder.*events and the return status forreturn.*events.datacarries event-specific fields. Fororder.failedit includeserror_typeanderror.
Complete event list
Order lifecycle:order.started, order.placed, order.failed, order.tracking_received,
order.delivered, order.cancelled
Return lifecycle:
return.created, return.approved, return.denied, return.credited
When mapping v1 event names in Phase 6, map only to names in this list. Any v1
event with no equivalent here goes to MIGRATION_GAPS.md rather than a guessed name.
Phase 0 — Ground in the current docs
Before writing any code, fetch the live v2 documentation. Do not rely on what you remember about the Zinc API; v2 ships changes frequently. Fetch at minimum:https://www.zinc.com/docs/llms.txt— the full documentation indexhttps://www.zinc.com/docs/versions/latest.json— the OpenAPI spec, the source of truth for field names and types- This page and the migration reference
- Endpoint pages for any endpoints this codebase uses. At minimum:
https://www.zinc.com/docs/v2/api-reference/introduction/authentication.mdhttps://www.zinc.com/docs/v2/api-reference/orders/create-order.mdhttps://www.zinc.com/docs/v2/api-reference/orders/get-order.mdhttps://www.zinc.com/docs/v2/api-reference/orders/cancel-order.mdhttps://www.zinc.com/docs/v2/api-reference/introduction/webhooks.mdhttps://www.zinc.com/docs/v2/api-reference/introduction/error-handling.mdhttps://www.zinc.com/docs/v2/api-reference/introduction/idempotency.mdhttps://www.zinc.com/docs/v2/api-reference/introduction/sandbox.mdhttps://www.zinc.com/docs/v2/api-reference/returns/create-return.md(plus get-return, list-returns)https://www.zinc.com/docs/v2/api-reference/products/get-product.md,get-product-offers.md,search.md
Phase 1 — Repo setup
Read-only confirmation. Stop and ask the human if any of these are unclear:- Identify the repo’s language(s) (Python / Node / Ruby / Go / PHP / etc.) and HTTP client patterns (
requests,axios,fetch, rawcurl, an SDK). - Identify the existing test harness — you’ll run it as validation in Phase 8.
- Create a new branch
zinc-v2-migration.
Phase 2 — Discovery → MIGRATION_INVENTORY.md
Search the repo for every v1 touchpoint. Inventory includes code paths, config, and persistence layer — not just HTTP call sites.
Code patterns:
- URL strings containing
api.zinc.io(any path) - URL strings containing
/v0/,/v1/, or/v2/near an HTTP call - Headers / variables named
client_token,ZINC_CLIENT_TOKEN,zinc_token,Authorization: Basic … - Imports of any v1 SDK:
zinc,@zinc/api,zinc-api,zincapi, etc. request_idpolling loops — v1 returned{"request_id": "..."}from order creation and required pollingGET /v1/orders/{request_id}; while in flight, that endpoint returned therequest_processingerror code rather than a real status- Webhook handler routes whose payloads or paths reference v1 event names:
order_placed,order_failed,tracking_obtained,tracking_updated,status_updated,case_updated,return_placed,return_failed,request_succeeded,request_failed
retailer, product_id, seller_selection_criteria, shipping_method, retailer_credentials, payment_method, billing_address, is_gift, gift_message, client_notes, addax, webhooks (v1 accepted per-request webhook URLs in the order body), max_price
v1 error / status codes to grep for:
_type: "error", request_processing, aborted_request, invalid_login, max_price_exceeded
Persistence:
- Database columns or models storing
request_id, v1 status strings (e.g.pending,submitted,placed), or v1 error codes — these may need a schema migration to hold v2’s UUID order IDs and the new status enum. - Migration shape: keep v1 columns readable during the transition window (existing in-flight v1 orders shouldn’t break); add v2 columns alongside.
- Environment variables,
.env*files, secret-manager templates, CI configs holding Zinc client tokens.
- Any per-environment config (Stripe-style keys, Slack channels, etc.) that points to Zinc — note which environments exist so the agent doesn’t accidentally mix test and prod keys later.
MIGRATION_INVENTORY.md at the repo root:
chore(zinc): inventory v1 call sites for v2 migration.
If the inventory contains zero rows, stop — there are no v1 calls to migrate; surface that to the human.
Phase 3 — Auth and base URL
One commit, repo-wide:Add or rename env vars
ZINC_API_KEY (the zn_live_* / zn_test_* bearer token) and add ZINC_BASE_URL (the v2 production host; default to a placeholder and flag for human confirmation in MIGRATION_PREREQS.md). These env var names are a convention for the customer’s repo, not values the API defines. The key itself is minted in the dashboard, never invented by the agent.Remove the old auth config
ZINC_CLIENT_TOKEN and any basic-auth password vars from .env.example, config.{py,js,...}, CI configs, and secret-manager templates. Add a deprecation comment.Rewrite every HTTP-client construction site
Authorization: Bearer ${ZINC_API_KEY} instead of Authorization: Basic <base64(token)>.feat(zinc): switch to v2 bearer auth and base URL.
Phase 4 — Pre-flight checklist → MIGRATION_PREREQS.md
Write MIGRATION_PREREQS.md with the human-required steps from the pre-flight checklist in the reference. Tailor it to what discovery found.
docs(zinc): manual pre-flight checklist for v2 migration.
Phase 5 — Endpoint-by-endpoint port
For each row inMIGRATION_INVENTORY.md, apply the transformation from the endpoint mapping and request shape diffs in the reference. Group by resource and commit per resource:
feat(zinc): port order placement to v2 /ordersfeat(zinc): port returns to v2 /returnsfeat(zinc): port retailer credentials to managed-accounts modelfeat(zinc): port tracking reads to embedded order tracking
Per-call-site checklist
For each call site:URL change
- Leave the calling code intact.
- Add
# TODO(zinc-migration): no v2 equivalent for {endpoint} — see MIGRATION_GAPS.md. - Append a row to
MIGRATION_GAPS.md. Continue.
Request body transformation
Response body transformation
request_id, merchant_order_ids, _status, price_components, etc., and rewrite.Status string branches
if status == "placed" or similar, rewrite to the v2 enum value ("order_placed"). Centralise into a helper if there are >3 sites.Hard rules
Never inline credentials
Never inline credentials
retailer_credentials, replace it with a config reference (e.g. config.ZINC_MANAGED_ACCOUNT_<NAME>) and add a row to MIGRATION_PREREQS.md. Do not move secrets between files.Confirm max_price units
Confirm max_price units
Don't auto-construct product URLs you're unsure about
Don't auto-construct product URLs you're unsure about
product_id is being used and you can’t confidently identify the retailer (e.g. from a sibling retailer: "amazon" argument), flag it.Idempotency keys carry over
Idempotency keys carry over
idempotency_key is still supported on v2 /orders; pass it through. Drop it for endpoints where v1 had it and v2 doesn’t (returns).Phase 6 — Webhook handlers
Consolidate into a single handler
webhooks objects).Insert HMAC-SHA256 signature verification
ZINC_WEBHOOK_SECRET as the HMAC key, compute over the raw request body, and reject with 401 if the X-Webhook-Signature header doesn’t match. Use hmac.compare_digest (or the language equivalent) to avoid timing leaks.Map v1 event names to v2 event names
status_updated / case_updated / request_succeeded / request_failed / return_failed, add TODO(zinc-migration) + a MIGRATION_GAPS.md row.feat(zinc): consolidate webhook handlers for v2 single-URL model.
Phase 7 — Gaps review → MIGRATION_GAPS.md
By the end of Phase 6 you should have a populated MIGRATION_GAPS.md. Ensure each row has:
- File and line of the original v1 call
- The v1 endpoint or event involved
- A one-sentence description of what the customer was doing with it
- Your suggested workaround if any (e.g., “store
merchant_order_idlocally and look it up; v2 does not exposeinsert_merchant_order_id”), ornone — discuss with Zincif you have no good suggestion
docs(zinc): document migration gaps for human review.
Phase 8 — Validation
Drive scenarios with the dedicated test product URLs rather than placing real orders. Fetch the live catalog fromGET /orders/test-products and exercise at minimum:
| Test product | What it exercises |
|---|---|
https://zinc.com/shop/products/test-success | Full happy path through order_placed, tracking numbers, and price components |
https://zinc.com/shop/products/test-invalid-address | Synchronous failure — rejected at order-creation time |
https://zinc.com/shop/products/test-url-unreachable | Synchronous failure |
https://zinc.com/shop/products/test-insufficient-funds | Synchronous failure |
https://zinc.com/shop/products/test-out-of-stock | Asynchronous failure — order creates successfully, then fails during processing and arrives as an order.failed webhook |
https://zinc.com/shop/products/test-price-exceeded | Asynchronous failure |
https://zinc.com/shop/products/test-invalid-variant | Asynchronous failure |
https://zinc.com/shop/products/test-shipping-unavailable | Asynchronous failure |
Confirm pre-flight is complete
MIGRATION_PREREQS.md are ticked, env vars are set in .env.test or equivalent.Run the customer's test suite against the v2 sandbox
ZINC_TEST_API_KEY and ZINC_BASE_URL. Sandbox is the same base URL as production — the zn_test_* key prefix alone determines test mode.Exercise the full lifecycle with the test products
test-success → every synchronous and asynchronous failure scenario → (if used) cancel and return flows. Confirm webhook signature verification passes on real sandbox deliveries, not just unit-test fixtures.Tail webhook-receiver logs during the test run
docs(zinc): migration report.
What to do when stuck
The reference disagrees with the customer's understanding
The reference disagrees with the customer's understanding
Customer code references an endpoint not in the guide
Customer code references an endpoint not in the guide
MIGRATION_GAPS.md with endpoint not documented in migration guide. Do not guess.Repeated identical edits across files
Repeated identical edits across files
lib/, clients/, services/zinc* before mass-editing.Tests fail in ways unrelated to the migration
Tests fail in ways unrelated to the migration
Output files summary
By the end of the migration, the customer’s repo has these new top-level files:| File | Purpose |
|---|---|
MIGRATION_INVENTORY.md | Every v1 call site, status per phase |
MIGRATION_PREREQS.md | Human checklist for dashboard / wallet / credentials setup |
MIGRATION_GAPS.md | Endpoints with no v2 equivalent + suggested workarounds |
MIGRATION_REPORT.md | Final summary |
zinc-v2-migration, ready for the customer’s normal PR review process.
