{"openapi":"3.1.0","info":{"title":"API Testing v1","version":"1.0.0","description":"Public and JWT-authenticated REST API built with Hono, deployed on Cloudflare Workers with D1 storage. Each table is capped at 100 rows; the oldest rows are deleted automatically before insert."},"servers":[{"url":"/"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"User":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"name":{"type":"string"},"role":{"type":"string","enum":["user","admin"]},"created_at":{"type":"integer","description":"Unix epoch milliseconds"}},"required":["id","email","name","role","created_at"]},"UserCreate":{"type":"object","properties":{"email":{"type":"string","format":"email"},"name":{"type":"string"},"password":{"type":"string","minLength":8,"maxLength":128}},"required":["email","name","password"]},"UserUpdate":{"type":"object","properties":{"email":{"type":"string","format":"email"},"name":{"type":"string"},"password":{"type":"string","minLength":8,"maxLength":128},"role":{"type":"string","enum":["user","admin"]}},"minProperties":1},"Product":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"price":{"type":"number"},"stock":{"type":"integer"},"created_at":{"type":"integer","description":"Unix epoch milliseconds"}},"required":["id","name","description","price","stock","created_at"]},"ProductCreate":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string","default":""},"price":{"type":"number","exclusiveMinimum":0},"stock":{"type":"integer","minimum":0,"default":0}},"required":["name","price"]},"ProductUpdate":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"price":{"type":"number","exclusiveMinimum":0},"stock":{"type":"integer","minimum":0}},"minProperties":1},"Transaction":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"product_id":{"type":"string","format":"uuid"},"quantity":{"type":"integer","exclusiveMinimum":0},"total":{"type":"number"},"status":{"type":"string","enum":["pending","completed","cancelled"]},"created_at":{"type":"integer","description":"Unix epoch milliseconds"}},"required":["id","user_id","product_id","quantity","total","status","created_at"]},"TransactionCreate":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid"},"product_id":{"type":"string","format":"uuid"},"quantity":{"type":"integer","exclusiveMinimum":0}},"required":["user_id","product_id","quantity"]},"TransactionUpdate":{"type":"object","properties":{"status":{"type":"string","enum":["pending","completed","cancelled"]},"quantity":{"type":"integer","exclusiveMinimum":0}},"minProperties":1},"Login":{"type":"object","properties":{"email":{"type":"string","format":"email"},"password":{"type":"string"}},"required":["email","password"]},"AuthPayload":{"type":"object","properties":{"token":{"type":"string"},"user":{"$ref":"#/components/schemas/User"}},"required":["token","user"]},"DeletedPayload":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"]},"OkUser":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/User"}},"required":["success","data"]},"OkUserList":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/User"}}},"required":["success","data"]},"OkProduct":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Product"}},"required":["success","data"]},"OkProductList":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Product"}}},"required":["success","data"]},"OkTransaction":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Transaction"}},"required":["success","data"]},"OkTransactionList":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Transaction"}}},"required":["success","data"]},"OkAuth":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/AuthPayload"}},"required":["success","data"]},"OkDeleted":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/DeletedPayload"}},"required":["success","data"]},"Error":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"}},"required":["success","error"]}}},"paths":{"/":{"get":{"summary":"Documentation","responses":{"200":{"description":"HTML documentation page"}}}},"/openapi.json":{"get":{"summary":"OpenAPI specification","responses":{"200":{"description":"OpenAPI 3.1 JSON","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/auth/register":{"post":{"summary":"Register a new user","tags":["auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkAuth"}}}},"409":{"description":"Email already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/login":{"post":{"summary":"Log in","tags":["auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Login"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkAuth"}}}},"401":{"description":"Invalid email or password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/users":{"get":{"summary":"List users","tags":["users"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkUserList"}}}}}},"post":{"summary":"Create a user","tags":["users"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkUser"}}}},"409":{"description":"Email already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/users/{id}":{"get":{"summary":"Get a user by ID","tags":["users"],"parameters":[{"$ref":"#/components/parameters/UserId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkUser"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a user","tags":["users"],"parameters":[{"$ref":"#/components/parameters/UserId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdate"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkUser"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a user","tags":["users"],"parameters":[{"$ref":"#/components/parameters/UserId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkDeleted"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/products":{"get":{"summary":"List products","tags":["products"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkProductList"}}}}}},"post":{"summary":"Create a product","tags":["products"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCreate"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkProduct"}}}}}}},"/api/v1/products/{id}":{"get":{"summary":"Get a product by ID","tags":["products"],"parameters":[{"$ref":"#/components/parameters/ProductId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkProduct"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a product","tags":["products"],"parameters":[{"$ref":"#/components/parameters/ProductId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductUpdate"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkProduct"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a product","tags":["products"],"parameters":[{"$ref":"#/components/parameters/ProductId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkDeleted"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/transactions":{"get":{"summary":"List transactions","tags":["transactions"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkTransactionList"}}}}}},"post":{"summary":"Create a transaction","tags":["transactions"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionCreate"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkTransaction"}}}},"404":{"description":"User or product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Insufficient stock","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/transactions/{id}":{"get":{"summary":"Get a transaction by ID","tags":["transactions"],"parameters":[{"$ref":"#/components/parameters/TransactionId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkTransaction"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a transaction","tags":["transactions"],"parameters":[{"$ref":"#/components/parameters/TransactionId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionUpdate"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkTransaction"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a transaction","tags":["transactions"],"parameters":[{"$ref":"#/components/parameters/TransactionId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkDeleted"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/users":{"get":{"summary":"List users (authenticated)","tags":["auth-users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkUserList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a user (authenticated)","tags":["auth-users"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreate"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkUser"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Email already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/users/{id}":{"get":{"summary":"Get a user by ID (authenticated)","tags":["auth-users"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/UserId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkUser"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a user (authenticated)","tags":["auth-users"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/UserId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserUpdate"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkUser"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a user (authenticated)","tags":["auth-users"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/UserId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkDeleted"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/products":{"get":{"summary":"List products (authenticated)","tags":["auth-products"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkProductList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a product (authenticated)","tags":["auth-products"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductCreate"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkProduct"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/products/{id}":{"get":{"summary":"Get a product by ID (authenticated)","tags":["auth-products"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/ProductId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkProduct"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update a product (authenticated)","tags":["auth-products"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/ProductId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductUpdate"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkProduct"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a product (authenticated)","tags":["auth-products"],"security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/ProductId"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkDeleted"}}}},"400":{"description":"Invalid id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"parameters":{"UserId":{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"ProductId":{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"TransactionId":{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}}}