{"openapi":"3.0.3","info":{"title":"WeMix API","description":"API for WeMix concrete ordering, contacts, orders, and integrations.\n\n**API keys (internal & external):**\n- Send `X-API-Key: <your-key>` or `Authorization: Bearer <your-key>` on requests.\n- Create keys: set `API_KEY_ADMIN_SECRET` in env, then POST /api-keys with header `X-Admin-Secret: <that-secret>` and body `{ \"name\": \"My key\", \"scope\": \"write\" }`. The response includes `apiKey` (plain) once—store it securely.\n- List/revoke: GET/DELETE /api-keys and /api-keys/{id} with `X-Admin-Secret`.","version":"1.0.0","contact":{"name":"WeMix"}},"servers":[{"url":"/api","description":"Current origin"}],"tags":[{"name":"Health","description":"Health and status"},{"name":"Order requests","description":"Concrete order requests (wizard + advanced)"},{"name":"Contacts","description":"Contact form submissions"},{"name":"Demo requests","description":"Book-a-demo submissions"},{"name":"Calculator","description":"Concrete volume calculator"},{"name":"Auth","description":"Login, magic link, OTP"},{"name":"API keys","description":"Manage API keys (admin only)"},{"name":"Resources","description":"Drivers, franchises, orders, projects, trucks, users"},{"name":"Stripe","description":"Checkout session"}],"security":[{"ApiKeyAuth":[]},{"BearerAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key (e.g. wmx_...) for programmatic access. Create keys via POST /api-keys (requires X-Admin-Secret)."},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT from /api/auth/login or API key value in Bearer header."},"AdminSecret":{"type":"apiKey","in":"header","name":"X-Admin-Secret","description":"Required only for API key management (create/list/revoke). Set API_KEY_ADMIN_SECRET in env."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}},"OrderRequestSummary":{"type":"object","properties":{"_id":{"type":"string"},"status":{"type":"string","enum":["new","contacted","scheduled","completed","cancelled"]},"source":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"paymentIntent":{"type":"string","enum":["pay_now","pay_later"]}}}}},"paths":{"/health":{"get":{"tags":["Health"],"summary":"Health check","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"database":{"type":"string"},"timestamp":{"type":"string"}}}}}}}}},"/order-requests":{"get":{"tags":["Order requests"],"summary":"List orders by email or validate ZIP","parameters":[{"name":"email","in":"query","schema":{"type":"string"},"description":"List orders for this email (requires API key for programmatic use)"},{"name":"zip","in":"query","schema":{"type":"string"},"description":"Validate serving area ZIP"}],"responses":{"200":{"description":"Orders list or zip validation result"}}},"post":{"tags":["Order requests"],"summary":"Create order request","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["name","email","phone","message","address","city","state","zip","userType","buildCategory","buildSubType","strength"],"properties":{"userType":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"},"buildCategory":{"type":"string"},"buildSubType":{"type":"string"},"unloadingType":{"type":"string"},"slumpSize":{"type":"string"},"hoseDiameter":{"type":"string"},"strength":{"type":"string"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"message":{"type":"string"},"advancedForm":{"type":"object"},"source":{"type":"string","enum":["order-onboarding","order-onboarding-pay-later"]}}}}}},"responses":{"201":{"description":"Order created"},"400":{"description":"Validation error"}}}},"/order-requests/{id}":{"get":{"tags":["Order requests"],"summary":"Get order by ID","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Order details"},"404":{"description":"Not found"}}}},"/contacts":{"get":{"tags":["Contacts"],"summary":"List contact submissions","parameters":[{"name":"status","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"skip","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"Contacts list"}}},"post":{"tags":["Contacts"],"summary":"Create contact submission","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["name","email","message"],"properties":{"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"subject":{"type":"string"},"company":{"type":"string"},"message":{"type":"string"},"source":{"type":"string"}}}}}},"responses":{"201":{"description":"Contact created"}}}},"/contacts/{id}":{"get":{"tags":["Contacts"],"summary":"Get contact by ID","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Contact"}}}},"/demo-requests":{"post":{"tags":["Demo requests"],"summary":"Create demo request","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["name","email","phone"],"properties":{"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"company":{"type":"string"},"message":{"type":"string"},"source":{"type":"string"}}}}}},"responses":{"201":{"description":"Demo request created"}}}},"/calculate-concrete":{"post":{"tags":["Calculator"],"summary":"Calculate concrete volume","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["shapeType"],"properties":{"shapeType":{"type":"string","enum":["slab","footing","column","wall","stairs","curb"]},"length":{"type":"number"},"width":{"type":"number"},"depthIn":{"type":"number"},"diameterIn":{"type":"number"},"height":{"type":"number"},"curbTopWidth":{"type":"number"},"curbBottomWidth":{"type":"number"},"curbHeight":{"type":"number"},"units":{"type":"string","enum":["imperial","metric"]},"wasteFactorPct":{"type":"number"},"truckMaxCy":{"type":"number"}}}}}},"responses":{"200":{"description":"Calculation result with base_cy, total_cy, weight_lbs, recommendation"}}}},"/auth/login":{"post":{"tags":["Auth"],"summary":"Login (email + password)","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string"},"password":{"type":"string"},"role":{"type":"string"}}}}}},"responses":{"200":{"description":"Token and user"}}}},"/auth/enabled-roles":{"get":{"tags":["Auth"],"summary":"List enabled roles","responses":{"200":{"description":"enabledRoles array"}}}},"/auth/register":{"post":{"tags":["Auth"],"summary":"Register","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"User created"}}}},"/auth/guest":{"post":{"tags":["Auth"],"summary":"Guest sign-in","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Token"}}}},"/auth/send-magic-link":{"post":{"tags":["Auth"],"summary":"Send magic link","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"role":{"type":"string"}}}}}},"responses":{"200":{"description":"Sent"}}}},"/auth/send-otp":{"post":{"tags":["Auth"],"summary":"Send OTP","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"role":{"type":"string"}}}}}},"responses":{"200":{"description":"OTP sent"}}}},"/auth/verify-magic-link":{"post":{"tags":["Auth"],"summary":"Verify magic link token","responses":{"302":{"description":"Redirect with cookie"}}}},"/auth/verify-otp":{"post":{"tags":["Auth"],"summary":"Verify OTP","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Token"}}}},"/api-keys":{"get":{"tags":["API keys"],"summary":"List API keys (admin)","security":[{"AdminSecret":[]}],"responses":{"200":{"description":"apiKeys array"},"401":{"description":"X-Admin-Secret required"}}},"post":{"tags":["API keys"],"summary":"Create API key (admin)","security":[{"AdminSecret":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"scope":{"type":"string","enum":["read","write","admin"]}}}}}},"responses":{"201":{"description":"apiKey (plain) returned once; store securely"},"401":{"description":"X-Admin-Secret required"}}}},"/api-keys/{id}":{"delete":{"tags":["API keys"],"summary":"Revoke API key (admin)","security":[{"AdminSecret":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Revoked"},"401":{"description":"X-Admin-Secret required"}}}},"/stripe/create-checkout-session":{"post":{"tags":["Stripe"],"summary":"Create Stripe checkout session","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"metadata":{"type":"object"}}}}}},"responses":{"200":{"description":"url for redirect"}}}},"/drivers":{"get":{"tags":["Resources"],"summary":"List drivers"},"post":{"tags":["Resources"],"summary":"Create driver"}},"/drivers/{id}":{"get":{"tags":["Resources"],"summary":"Get driver"},"put":{"tags":["Resources"],"summary":"Update driver"},"delete":{"tags":["Resources"],"summary":"Delete driver"}},"/franchises":{"get":{"tags":["Resources"],"summary":"List franchises"},"post":{"tags":["Resources"],"summary":"Create franchise"}},"/franchises/{id}":{"get":{"tags":["Resources"],"summary":"Get franchise"},"put":{"tags":["Resources"],"summary":"Update franchise"},"delete":{"tags":["Resources"],"summary":"Delete franchise"}},"/orders":{"get":{"tags":["Resources"],"summary":"List orders"},"post":{"tags":["Resources"],"summary":"Create order"}},"/orders/{id}":{"get":{"tags":["Resources"],"summary":"Get order"},"put":{"tags":["Resources"],"summary":"Update order"},"delete":{"tags":["Resources"],"summary":"Delete order"}},"/projects":{"get":{"tags":["Resources"],"summary":"List projects"},"post":{"tags":["Resources"],"summary":"Create project"}},"/projects/{id}":{"get":{"tags":["Resources"],"summary":"Get project"},"put":{"tags":["Resources"],"summary":"Update project"},"delete":{"tags":["Resources"],"summary":"Delete project"}},"/trucks":{"get":{"tags":["Resources"],"summary":"List trucks"},"post":{"tags":["Resources"],"summary":"Create truck"}},"/trucks/{id}":{"get":{"tags":["Resources"],"summary":"Get truck"},"put":{"tags":["Resources"],"summary":"Update truck"},"delete":{"tags":["Resources"],"summary":"Delete truck"}},"/users":{"get":{"tags":["Resources"],"summary":"List users"},"post":{"tags":["Resources"],"summary":"Create user"}},"/users/{id}":{"get":{"tags":["Resources"],"summary":"Get user"},"put":{"tags":["Resources"],"summary":"Update user"},"delete":{"tags":["Resources"],"summary":"Delete user"}}}}