OctoWiki
Memory Appendix

Neocurrency Spec Drift

NeoCurrency production wire shapes contradict the OpenAPI spec in several places — the spec is unreliable. Prefer json.RawMessage for fields where prod/spec dis

Source memory file: project_neocurrency_spec_drift.md · Category: Project / investigation This is a verbatim dump of Claude's persistent memory for the Octopus project. Rendered inside a code block so nothing is altered.

---
name: neocurrency-spec-drift
description: NeoCurrency production wire shapes contradict the OpenAPI spec in several places — the spec is unreliable. Prefer json.RawMessage for fields where prod/spec disagree.
metadata: 
  node_type: memory
  type: project
  originSessionId: c6efcf05-5585-4e8c-a071-39a96a3c0386
---

NeoCurrency's OpenAPI spec at `docs/neocurrency/openapi.json` does **not** reliably describe the live API. Multiple wire-shape contradictions confirmed against the live sandbox/production responses:

| Field / endpoint | Spec says | Production returns |
|---|---|---|
| `POST /get-token``success` | object `{access_token: "..."}` | array `[{access_token: "..."}]` |
| `/get-token` token | "non-expiring" per docs | JWT with `exp = iat + 24h` |
| `/brands[].step_size` | string (e.g. `"0.01"`) | `null` (often), or string in some sandbox brands |
| `/brands[].expiry_in_months` | string | sometimes a number, sometimes empty string |

**Why:** The spec hasn't been kept in sync with prod; trusting it leads to `cannot unmarshal X into Go struct field` panics during catalog sync (saw this with `expiry_in_months` on 2026-05-15).

**How to apply:**
- For NeoCurrency only: when adding/changing a field in `services/external_vendors/vouchers/neo_vendor.go` types (`neoBrand`, `neoOrderBrandResponse`, etc.), prefer **`json.RawMessage`** for any field that's not actively consumed downstream — this tolerates type drift without crashing the catalog sync.
- If a field IS consumed, write an explicit `UnmarshalJSON` that accepts both shapes (see how `success` is decoded in [[neocurrency-vendor-integration]] — array-with-fallback).
- When the spec and prod disagree, **prod wins**. Update the Go DTO comment to call out the divergence (we already do this for `success` and `step_size`).
- The 401-auto-retry in `authedDo` covers the 24h JWT expiry — don't add proactive token refresh.

Related:
- [[feedback_no_speculative_vendor_paths]] — same principle: only handle shapes we actually receive
- The Postman collection lives at `docs/neocurrency/NeoCurrency.postman_collection.json` and has been updated to reflect array-wrapped `success`