{"openapi":"3.0.3","info":{"title":"Due-Date & Business-Day API","version":"0.3.0","description":"Business-day math, payment-term due dates and holiday calendars. Every /v1 route is also served keyless at /web/v1 (IP rate-limited, 60/min by default; used by the web calculator); /web/v1 has no /usage or /batch. Results depend on open-source holiday data; verify legally binding deadlines against an official source."},"servers":[{"url":"http://localhost:8787"}],"security":[{"bearer":[]},{"apiKey":[]}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer"},"apiKey":{"type":"apiKey","in":"header","name":"x-api-key"}},"schemas":{"ErrorCode":{"type":"string","enum":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_roll","invalid_term","unsupported_country","unsupported_region","invalid_input","invalid_json","empty_csv","missing_column","missing_api_key","invalid_api_key","quota_exceeded","rate_limited","payload_too_large","too_many_rows","unsupported_media_type","not_found","internal_error","invalid_email","email_taken","turnstile_failed","no_account","key_limit_reached","last_key","invalid_plan","already_subscribed","no_billing_account","billing_not_configured","stripe_error","invalid_signature"]},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string"},"details":{"type":"object","description":"e.g. { param } for parameter errors, { column } or { maxRows } for batch errors","additionalProperties":true}}}},"example":{"error":{"code":"invalid_integer","message":"'days' must be a whole number (got \"2.5\")","details":{"param":"days"}}}},"SkippedDay":{"type":"object","required":["date","reason"],"properties":{"date":{"type":"string","format":"date","example":"2026-11-20"},"reason":{"type":"string","enum":["weekend","holiday","custom-holiday"]},"name":{"type":"string","description":"Holiday name (holiday only)"}}},"PaymentTerm":{"type":"object","description":"Parsed term. kind: net | netbd | eom | discount (discount has percent, discountDays, discountFrom 'invoice'|'eom', net)","required":["kind"],"properties":{"kind":{"type":"string","enum":["net","netbd","eom","discount"]},"days":{"type":"integer"},"percent":{"type":"number"},"discountDays":{"type":"integer"},"discountFrom":{"type":"string","enum":["invoice","eom"]},"net":{"type":"object"}},"additionalProperties":true},"AddBusinessDaysResult":{"type":"object","required":["date","days","result","weekday"],"properties":{"date":{"type":"string","format":"date","example":"2026-11-20"},"days":{"type":"integer"},"result":{"type":"string","format":"date","example":"2026-11-20"},"weekday":{"type":"string"},"skipped":{"type":"array","items":{"$ref":"#/components/schemas/SkippedDay"},"description":"Present only with explain=true"}}},"BusinessDaysBetweenResult":{"type":"object","required":["start","end","businessDays","calendarDays","convention"],"properties":{"start":{"type":"string","format":"date","example":"2026-11-20"},"end":{"type":"string","format":"date","example":"2026-11-20"},"businessDays":{"type":"integer"},"calendarDays":{"type":"integer"},"convention":{"type":"string","example":"start exclusive, end inclusive"},"skipped":{"type":"array","items":{"$ref":"#/components/schemas/SkippedDay"},"description":"Present only with explain=true"}}},"IsBusinessDayResult":{"type":"object","required":["date","weekday","isBusinessDay","isHoliday","reason"],"properties":{"date":{"type":"string","format":"date","example":"2026-11-20"},"weekday":{"type":"string"},"isBusinessDay":{"type":"boolean"},"isHoliday":{"type":"boolean"},"reason":{"$ref":"#/components/schemas/SkippedDay","nullable":true}}},"TermBase":{"type":"object","required":["invoiceDate","term","parsedTerm","description","roll","dueDate","nominalDueDate"],"properties":{"invoiceDate":{"type":"string","format":"date","example":"2026-11-20"},"term":{"type":"string","example":"2/10 Net 30"},"parsedTerm":{"$ref":"#/components/schemas/PaymentTerm"},"description":{"type":"string"},"roll":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"]},"dueDate":{"type":"string","format":"date","example":"2026-11-20"},"nominalDueDate":{"type":"string","format":"date","example":"2026-11-20","description":"Due date before weekend/holiday adjustment (roll=none). Equals dueDate for business-day terms (Net N BD)."},"skipped":{"type":"array","items":{"$ref":"#/components/schemas/SkippedDay"},"description":"Non-business days from invoice date through the later of nominal/final due date. Present only with explain=true"},"rollSkipped":{"type":"array","items":{"$ref":"#/components/schemas/SkippedDay"},"description":"Non-business days that caused the move from nominalDueDate to dueDate (empty if not moved). Present only with explain=true"}}},"DueDateResult":{"allOf":[{"$ref":"#/components/schemas/TermBase"},{"type":"object","required":["weekday"],"properties":{"weekday":{"type":"string"},"discountDate":{"type":"string","format":"date","example":"2026-11-20","description":"Discount terms only"},"discountPercent":{"type":"number","description":"Discount terms only"}}}]},"TermDatesResult":{"allOf":[{"$ref":"#/components/schemas/TermBase"},{"type":"object","required":["dueWeekday","discountDate","discountWeekday","discountPercent"],"properties":{"dueWeekday":{"type":"string"},"discountDate":{"type":"string","format":"date","example":"2026-11-20","nullable":true},"discountWeekday":{"type":"string","nullable":true},"discountPercent":{"type":"number","description":"0 when no discount"}}}]},"Holiday":{"type":"object","required":["date","name","type"],"properties":{"date":{"type":"string","format":"date","example":"2026-11-20"},"name":{"type":"string"},"type":{"type":"string","enum":["public","bank"]}}},"HolidaysResult":{"type":"object","required":["country","region","year","holidays"],"properties":{"country":{"type":"string"},"region":{"type":"string","nullable":true},"year":{"type":"integer"},"holidays":{"type":"array","items":{"$ref":"#/components/schemas/Holiday"}}}},"UsageResult":{"type":"object","required":["plan","period","used","limit","remaining"],"properties":{"plan":{"type":"string"},"period":{"type":"string","example":"2026-11"},"used":{"type":"integer"},"limit":{"type":"integer"},"remaining":{"type":"integer"}}},"BatchRow":{"type":"object","properties":{"row":{"type":"integer","description":"CSV line number (header = 1)"},"invoice_date":{"type":"string"},"term":{"type":"string"},"country":{"type":"string"},"region":{"type":"string"},"due_date":{"type":"string"},"due_weekday":{"type":"string"},"discount_date":{"type":"string"},"discount_percent":{"oneOf":[{"type":"number"},{"type":"string"}]},"error":{"type":"string","description":"'<code>: <message>' or empty"}}},"Signup":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","maxLength":254},"turnstileToken":{"type":"string","description":"Required only when the server has Turnstile enabled"}}},"SignupResult":{"type":"object","required":["accountId","email","plan","monthlyLimit","key","keyId","keyPrefix"],"properties":{"accountId":{"type":"string","example":"acct_0123456789abcdef"},"email":{"type":"string"},"plan":{"type":"string","example":"free"},"monthlyLimit":{"type":"integer","example":1000},"key":{"type":"string","example":"dk_live_0123456789abcdef0123456789abcdef","description":"Shown ONCE. Only a SHA-256 hash is stored."},"keyId":{"type":"string"},"keyPrefix":{"type":"string"},"note":{"type":"string"}}},"KeySummary":{"type":"object","required":["id","keyPrefix","createdAt","current"],"properties":{"id":{"type":"string","example":"key_0a1b2c3d4e5f"},"keyPrefix":{"type":"string","example":"dk_live_0123"},"label":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"current":{"type":"boolean","description":"True for the key used on this request"}}},"Account":{"type":"object","required":["id","email","plan","planName","usage","maxKeys","keys","billingLinked"],"properties":{"id":{"type":"string"},"email":{"type":"string"},"plan":{"type":"string","enum":["free","starter","team","business"]},"planName":{"type":"string"},"planExpiresAt":{"type":"string","format":"date-time","nullable":true,"description":"Set when a canceled subscription still runs until period end"},"usage":{"$ref":"#/components/schemas/UsageResult"},"billingLinked":{"type":"boolean"},"maxKeys":{"type":"integer"},"keys":{"type":"array","items":{"$ref":"#/components/schemas/KeySummary"}},"subscription":{"type":"object","nullable":true,"properties":{"status":{"type":"string","example":"active"},"plan":{"type":"string"},"currentPeriodEnd":{"type":"string","format":"date-time","nullable":true},"cancelAtPeriodEnd":{"type":"boolean"}}}}},"NewKey":{"type":"object","required":["id","key","keyPrefix","createdAt"],"properties":{"id":{"type":"string"},"key":{"type":"string","description":"Shown ONCE"},"keyPrefix":{"type":"string"},"label":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"note":{"type":"string"}}},"RedirectSession":{"type":"object","required":["id","url"],"properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri","description":"Send the browser here (Stripe-hosted page)"},"plan":{"type":"string"}}},"BatchResult":{"type":"object","required":["rows","errors","results"],"properties":{"rows":{"type":"integer"},"errors":{"type":"integer"},"results":{"type":"array","items":{"$ref":"#/components/schemas/BatchRow"}}}}},"responses":{"Error":{"description":"Error (see error.code)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"TooManyRequests":{"description":"quota_exceeded (API key monthly limit) or rate_limited (web per-IP limit)","x-error-codes":["quota_exceeded","rate_limited"],"headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/add-business-days":{"get":{"operationId":"addBusinessDays","summary":"Add or subtract business days","parameters":[{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"}},{"name":"days","in":"query","required":true,"schema":{"type":"integer","minimum":-10000,"maximum":10000},"description":"Whole number; negative subtracts. Strings like \"+5\" or \"-3\" accepted; decimals give invalid_integer"},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"},{"name":"explain","in":"query","schema":{"type":"boolean","default":false},"description":"Include skipped non-business days ('true' or '1')"}],"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/AddBusinessDaysResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"operationId":"addBusinessDaysPost","summary":"Add or subtract business days (JSON body; body fields override query params)","parameters":[{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"}},{"name":"days","in":"query","required":true,"schema":{"type":"integer","minimum":-10000,"maximum":10000},"description":"Whole number; negative subtracts. Strings like \"+5\" or \"-3\" accepted; decimals give invalid_integer"},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"},{"name":"explain","in":"query","schema":{"type":"boolean","default":false},"description":"Include skipped non-business days ('true' or '1')"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","format":"date","example":"2026-11-20"},"days":{"type":"integer","minimum":-10000,"maximum":10000},"country":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"region":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"customHolidays":{"oneOf":[{"type":"array","items":{"type":"string","format":"date","example":"2026-11-20"}},{"type":"string"}]},"customWorkdays":{"oneOf":[{"type":"array","items":{"type":"string","format":"date","example":"2026-11-20"}},{"type":"string"}]},"weekend":{"oneOf":[{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},{"type":"string"}]},"explain":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/AddBusinessDaysResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/business-days-between":{"get":{"operationId":"businessDaysBetween","summary":"Count business days in (start, end]; range max 10 years","parameters":[{"name":"start","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"}},{"name":"end","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"}},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"},{"name":"explain","in":"query","schema":{"type":"boolean","default":false},"description":"Include skipped non-business days ('true' or '1')"}],"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/BusinessDaysBetweenResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"operationId":"businessDaysBetweenPost","summary":"Count business days in (start, end]; range max 10 years (JSON body; body fields override query params)","parameters":[{"name":"start","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"}},{"name":"end","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"}},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"},{"name":"explain","in":"query","schema":{"type":"boolean","default":false},"description":"Include skipped non-business days ('true' or '1')"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"start":{"type":"string","format":"date","example":"2026-11-20"},"end":{"type":"string","format":"date","example":"2026-11-20"},"country":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"region":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"customHolidays":{"oneOf":[{"type":"array","items":{"type":"string","format":"date","example":"2026-11-20"}},{"type":"string"}]},"customWorkdays":{"oneOf":[{"type":"array","items":{"type":"string","format":"date","example":"2026-11-20"}},{"type":"string"}]},"weekend":{"oneOf":[{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},{"type":"string"}]},"explain":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/BusinessDaysBetweenResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/is-business-day":{"get":{"operationId":"isBusinessDay","summary":"Check a single date","parameters":[{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"}},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"}],"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/IsBusinessDayResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"operationId":"isBusinessDayPost","summary":"Check a single date (JSON body; body fields override query params)","parameters":[{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"}},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","format":"date","example":"2026-11-20"},"country":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"region":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"customHolidays":{"oneOf":[{"type":"array","items":{"type":"string","format":"date","example":"2026-11-20"}},{"type":"string"}]},"customWorkdays":{"oneOf":[{"type":"array","items":{"type":"string","format":"date","example":"2026-11-20"}},{"type":"string"}]},"weekend":{"oneOf":[{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},{"type":"string"}]}}}}}},"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/IsBusinessDayResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/due-date":{"get":{"operationId":"dueDate","summary":"Due date for a payment term (Net 30, EOM+15, 2/10 Net 30, Net 10 BD)","parameters":[{"name":"invoiceDate","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"},"description":"Also accepted as 'invoice_date'"},{"name":"term","in":"query","required":true,"schema":{"type":"string","example":"2/10 Net 30"}},{"name":"roll","in":"query","schema":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"description":"Weekend/holiday adjustment for the due date"},{"name":"discountRoll","in":"query","schema":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"description":"Adjustment for the discount date (defaults to roll)"},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"},{"name":"explain","in":"query","schema":{"type":"boolean","default":false},"description":"Include skipped non-business days ('true' or '1')"}],"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/DueDateResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region","invalid_term","invalid_roll"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"operationId":"dueDatePost","summary":"Due date for a payment term (Net 30, EOM+15, 2/10 Net 30, Net 10 BD) (JSON body; body fields override query params)","parameters":[{"name":"invoiceDate","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"},"description":"Also accepted as 'invoice_date'"},{"name":"term","in":"query","required":true,"schema":{"type":"string","example":"2/10 Net 30"}},{"name":"roll","in":"query","schema":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"description":"Weekend/holiday adjustment for the due date"},{"name":"discountRoll","in":"query","schema":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"description":"Adjustment for the discount date (defaults to roll)"},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"},{"name":"explain","in":"query","schema":{"type":"boolean","default":false},"description":"Include skipped non-business days ('true' or '1')"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"invoiceDate":{"type":"string","format":"date","example":"2026-11-20"},"term":{"type":"string","example":"2/10 Net 30"},"roll":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"discountRoll":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"country":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"region":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"customHolidays":{"oneOf":[{"type":"array","items":{"type":"string","format":"date","example":"2026-11-20"}},{"type":"string"}]},"customWorkdays":{"oneOf":[{"type":"array","items":{"type":"string","format":"date","example":"2026-11-20"}},{"type":"string"}]},"weekend":{"oneOf":[{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},{"type":"string"}]},"explain":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/DueDateResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region","invalid_term","invalid_roll"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/term-dates":{"get":{"operationId":"termDates","summary":"Discount date + due date for a term","parameters":[{"name":"invoiceDate","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"},"description":"Also accepted as 'invoice_date'"},{"name":"term","in":"query","required":true,"schema":{"type":"string","example":"2/10 Net 30"}},{"name":"roll","in":"query","schema":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"description":"Weekend/holiday adjustment for the due date"},{"name":"discountRoll","in":"query","schema":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"description":"Adjustment for the discount date (defaults to roll)"},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"},{"name":"explain","in":"query","schema":{"type":"boolean","default":false},"description":"Include skipped non-business days ('true' or '1')"}],"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/TermDatesResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region","invalid_term","invalid_roll"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"operationId":"termDatesPost","summary":"Discount date + due date for a term (JSON body; body fields override query params)","parameters":[{"name":"invoiceDate","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-20"},"description":"Also accepted as 'invoice_date'"},{"name":"term","in":"query","required":true,"schema":{"type":"string","example":"2/10 Net 30"}},{"name":"roll","in":"query","schema":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"description":"Weekend/holiday adjustment for the due date"},{"name":"discountRoll","in":"query","schema":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"description":"Adjustment for the discount date (defaults to roll)"},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"},{"name":"explain","in":"query","schema":{"type":"boolean","default":false},"description":"Include skipped non-business days ('true' or '1')"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"invoiceDate":{"type":"string","format":"date","example":"2026-11-20"},"term":{"type":"string","example":"2/10 Net 30"},"roll":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"discountRoll":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"country":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"region":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"customHolidays":{"oneOf":[{"type":"array","items":{"type":"string","format":"date","example":"2026-11-20"}},{"type":"string"}]},"customWorkdays":{"oneOf":[{"type":"array","items":{"type":"string","format":"date","example":"2026-11-20"}},{"type":"string"}]},"weekend":{"oneOf":[{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},{"type":"string"}]},"explain":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/TermDatesResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region","invalid_term","invalid_roll"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/holidays":{"get":{"operationId":"listHolidays","summary":"List public/bank holidays (GET only)","parameters":[{"name":"country","in":"query","required":true,"schema":{"type":"string","example":"US"}},{"name":"region","in":"query","required":false,"schema":{"type":"string"}},{"name":"year","in":"query","required":false,"schema":{"type":"integer","minimum":1900,"maximum":2200},"description":"Defaults to the current UTC year"}],"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/HolidaysResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["missing_parameter","invalid_parameter","invalid_date","invalid_integer","out_of_range","invalid_input","invalid_json","unsupported_country","unsupported_region"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/usage":{"get":{"operationId":"getUsage","summary":"Current month usage for this key (counts as a request)","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/UsageResult"}}}}}},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/batch/due-dates":{"post":{"operationId":"batchDueDates","summary":"Batch due dates from CSV (header must include invoice_date, term; optional country, region, roll columns override defaults per row)","description":"Query params (or extra JSON body fields) set defaults for every row: country, region, roll, discountRoll, customHolidays, customWorkdays, weekend. Max 1000 rows by default and 2 MB body. Per-row errors go in the error column and do not fail the request.","parameters":[{"name":"format","in":"query","schema":{"type":"string","enum":["csv","json"]},"description":"Defaults to json if Accept includes application/json, else csv"},{"name":"roll","in":"query","schema":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"description":"Weekend/holiday adjustment for the due date"},{"name":"discountRoll","in":"query","schema":{"type":"string","enum":["none","following","modified-following","preceding","modified-preceding"],"default":"following"},"description":"Weekend/holiday adjustment for the due date"},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"US"},"description":"ISO country code (UK accepted for GB). Omit for weekends only."},{"name":"region","in":"query","schema":{"type":"string","pattern":"^[A-Za-z0-9-]{1,10}$","example":"NY"},"description":"State/region code; requires 'country'"},{"name":"customHolidays","in":"query","schema":{"type":"string"},"description":"Comma-separated YYYY-MM-DD dates, max 366 (JSON body: array)"},{"name":"customWorkdays","in":"query","schema":{"type":"string"},"description":"Dates forced to be business days, max 366 (JSON body: array)"},{"name":"weekend","in":"query","schema":{"type":"string","example":"0,6","default":"0,6"},"description":"Weekend day numbers, 0=Sun..6=Sat (cannot cover all 7)"}],"requestBody":{"required":true,"content":{"text/csv":{"schema":{"type":"string"},"example":"invoice_date,term\n2026-11-20,2/10 Net 30\n"},"text/plain":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object","properties":{"csv":{"type":"string"}},"required":["csv"],"additionalProperties":true}}}},"responses":{"200":{"description":"One result per row","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Monthly quota (API key) or per-minute limit (web)"},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets"},"X-Usage-Period":{"schema":{"type":"string","example":"2026-11"},"description":"API-key routes only"},"X-Plan":{"schema":{"type":"string","example":"free"},"description":"API-key routes only"},"X-Batch-Rows":{"schema":{"type":"integer"}},"X-Batch-Errors":{"schema":{"type":"integer"}}},"content":{"text/csv":{"schema":{"type":"string","description":"Columns: row,invoice_date,term,country,region,due_date,due_weekday,discount_date,discount_percent,error"}},"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/BatchResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["empty_csv","missing_column","missing_parameter","invalid_parameter","invalid_json"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"413":{"$ref":"#/components/responses/Error","x-error-codes":["payload_too_large","too_many_rows"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/signup":{"post":{"operationId":"signup","summary":"Create a Free account and API key (no auth). Rate-limited per IP (5/hour by default). One account per email (+tags and Gmail dots ignored).","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Signup"}}}},"responses":{"200":{"description":"Not used; success is 201"},"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/SignupResult"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["invalid_email","invalid_json"]},"403":{"$ref":"#/components/responses/Error","x-error-codes":["turnstile_failed"]},"409":{"$ref":"#/components/responses/Error","x-error-codes":["email_taken"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/v1/account":{"get":{"operationId":"getAccount","summary":"Plan, usage and active keys for the account owning this key (does not count against quota)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Account"}}}}}},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"403":{"$ref":"#/components/responses/Error","x-error-codes":["no_account"]}}}},"/v1/account/keys":{"post":{"operationId":"createKey","summary":"Create an additional key (for rotation: create, deploy, then revoke the old one). Limited per plan (Free 2, Starter 3, Team 10, Business 25).","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","maxLength":60}}}}}},"responses":{"200":{"description":"Not used; success is 201"},"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/NewKey"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["invalid_json"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"403":{"$ref":"#/components/responses/Error","x-error-codes":["no_account"]},"409":{"$ref":"#/components/responses/Error","x-error-codes":["key_limit_reached"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]}}}},"/v1/account/keys/{id}":{"delete":{"operationId":"revokeKey","summary":"Revoke one of your keys. The last active key cannot be revoked.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"key_0a1b2c3d4e5f"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"revoked":{"type":"boolean"}}}}}}}},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"403":{"$ref":"#/components/responses/Error","x-error-codes":["no_account"]},"404":{"$ref":"#/components/responses/Error","x-error-codes":["not_found"]},"409":{"$ref":"#/components/responses/Error","x-error-codes":["last_key"]}}}},"/v1/billing/checkout":{"post":{"operationId":"createCheckout","summary":"Start a Stripe Checkout session to subscribe to a paid plan","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan"],"properties":{"plan":{"type":"string","enum":["starter","team","business"]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/RedirectSession"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["invalid_plan","invalid_json"]},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"403":{"$ref":"#/components/responses/Error","x-error-codes":["no_account"]},"409":{"$ref":"#/components/responses/Error","x-error-codes":["already_subscribed"]},"415":{"$ref":"#/components/responses/Error","x-error-codes":["unsupported_media_type"]},"502":{"$ref":"#/components/responses/Error","x-error-codes":["stripe_error"]},"503":{"$ref":"#/components/responses/Error","x-error-codes":["billing_not_configured"]}}}},"/v1/billing/portal":{"post":{"operationId":"createPortal","summary":"Open the Stripe Customer Portal (change plan, update card, cancel, invoices)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/RedirectSession"}}}}}},"401":{"$ref":"#/components/responses/Error","x-error-codes":["missing_api_key","invalid_api_key"]},"403":{"$ref":"#/components/responses/Error","x-error-codes":["no_account"]},"409":{"$ref":"#/components/responses/Error","x-error-codes":["no_billing_account"]},"502":{"$ref":"#/components/responses/Error","x-error-codes":["stripe_error"]},"503":{"$ref":"#/components/responses/Error","x-error-codes":["billing_not_configured"]}}}},"/stripe/webhook":{"post":{"operationId":"stripeWebhook","summary":"Stripe webhook receiver (Stripe-Signature verified; 5-minute tolerance; idempotent per event id)","security":[],"description":"Handles checkout.session.completed, customer.subscription.created/updated/deleted and invoice.payment_failed. Not for direct use.","parameters":[{"name":"Stripe-Signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Received","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"boolean"},"handled":{"type":"boolean"},"duplicate":{"type":"boolean"}}}}}},"400":{"$ref":"#/components/responses/Error","x-error-codes":["invalid_signature","invalid_json","invalid_input"]},"503":{"$ref":"#/components/responses/Error","x-error-codes":["billing_not_configured"]}}}},"/signup":{"get":{"operationId":"signupPage","summary":"Signup + pricing web page (HTML); also served at /pricing","security":[],"responses":{"200":{"description":"HTML","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/health":{"get":{"operationId":"health","summary":"Liveness check","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}}}},"/openapi.json":{"get":{"operationId":"openapi","summary":"This document","security":[],"responses":{"200":{"description":"OpenAPI 3 document","content":{"application/json":{"schema":{"type":"object"}}}}}}}}}