Fix OpenAPI spec inaccuracies found by the onboarding test

- GET /v1/admin/licenses requires product_id (uuid), not a slug
- add the /v1/admin/licenses/search path (was referenced, never defined)
- drop the phantom GET /v1/admin/products (only POST exists; list is
  the public GET /v1/products)
- clarify product price_value (write field) vs legacy price_sats
This commit is contained in:
Grant
2026-06-16 22:48:09 -05:00
parent 7a1c70ab9b
commit be8688de80
+11 -9
View File
@@ -86,9 +86,9 @@ const SPEC_JSON: &str = r##"{
"slug": { "type": "string" },
"name": { "type": "string" },
"description": { "type": "string" },
"price_sats": { "type": "integer", "nullable": true },
"price_currency": { "type": "string", "enum": ["SAT", "USD", "EUR"], "nullable": true },
"price_value": { "type": "integer", "nullable": true },
"price_sats": { "type": "integer", "nullable": true, "description": "Legacy SAT price. Still accepted on create for backward compatibility; new callers should send price_value + price_currency instead. Also returned in responses (derived from price_value when that path is used)." },
"price_currency": { "type": "string", "enum": ["SAT", "USD", "EUR"], "nullable": true, "description": "Currency for price_value. Defaults to SAT." },
"price_value": { "type": "integer", "nullable": true, "description": "Write field: price in the smallest unit of price_currency (sats for SAT, cents for USD/EUR). Send together with price_currency." },
"active": { "type": "boolean" },
"entitlements_catalog": {
"type": "array",
@@ -263,7 +263,7 @@ const SPEC_JSON: &str = r##"{
"/v1/admin/licenses": {
"get": {
"summary": "List licenses",
"description": "Scope required: `licenses:read`. Filter by status, product_slug, buyer_email, expiring soon, etc. via query params.",
"description": "Scope required: `licenses:read`. Requires `product_id=<uuid>` (the product's UUID, not its slug); returns that product's licenses. Use `GET /v1/admin/licenses/search` to look up by buyer_email or invoice id.",
"responses": { "200": { "description": "License list" } }
},
"post": {
@@ -272,6 +272,13 @@ const SPEC_JSON: &str = r##"{
"responses": { "200": { "description": "Issued license" } }
}
},
"/v1/admin/licenses/search": {
"get": {
"summary": "Search licenses",
"description": "Scope required: `licenses:read`. Look up licenses by `buyer_email`, `nostr_npub`, or `invoice_id` (whichever is supplied). With no filter, returns the 100 most-recent licenses. The `license_key` is never returned here (only on issue / recover).",
"responses": { "200": { "description": "Matching licenses" } }
}
},
"/v1/admin/licenses/{id}/revoke": {
"post": {
"summary": "Revoke a license",
@@ -301,11 +308,6 @@ const SPEC_JSON: &str = r##"{
}
},
"/v1/admin/products": {
"get": {
"summary": "List products",
"description": "Scope required: `products:read`.",
"responses": { "200": { "description": "Product list" } }
},
"post": {
"summary": "Create a product",
"description": "Scope required: `products:write`.",