{"openapi":"3.1.0","info":{"title":"Jolly Raleigh Grokbot Quote Request API","version":"1.0.0","description":"Customer-authorized, email-only submissions that start the existing Christmas lighting quote workflow. A request acknowledgement is not a booking. Rolling limits: 60 API attempts/minute per shared network bucket and 600/minute globally; 5 requests/hour per shared network bucket; 3 requests/24 hours per reply inbox; 1/24 hours per property; 50/24 hours globally; at most 20 pending jobs. Malformed and unauthorized attempts count toward API ceilings. Honor Retry-After on 429 and 503."},"servers":[{"url":"https://staging.jollyraleigh.com/api/grokbot/v1"}],"paths":{"/requests":{"post":{"operationId":"createQuoteRequest","summary":"Start an email-only Christmas lighting quote","description":"Starts the existing quote generation workflow. There is no separate status endpoint. Reuse the same key and exact payload for retries. The returned quoteUrl is the supported way to view job progress and results. A 409 processing or needs_support response must not be worked around by creating a second request.","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":16,"maxLength":128,"pattern":"^[a-zA-Z0-9_-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["schemaVersion","customer","property","options","communication","authorization"],"properties":{"schemaVersion":{"const":"1"},"customer":{"type":"object","additionalProperties":false,"required":["name","replyEmail"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"replyEmail":{"type":"string","format":"email","maxLength":254}}},"property":{"type":"object","additionalProperties":false,"required":["addressLine1","city","state","postalCode"],"properties":{"addressLine1":{"type":"string","minLength":1,"maxLength":180},"city":{"type":"string","minLength":1,"maxLength":80},"state":{"type":"string","pattern":"^[A-Z]{2}$"},"postalCode":{"type":"string","pattern":"^\\d{5}(-\\d{4})?$"}}},"options":{"description":"Option A requests roofline only. Option B requests roofline, ridges, and front-facing gable. Trees and bushes are separate optional requests applied to selected options. Option IDs and scopes must each be unique.","type":"array","minItems":1,"maxItems":2,"uniqueItems":true,"items":{"type":"object","additionalProperties":false,"required":["id","scope"],"properties":{"id":{"type":"string","pattern":"^[A-Z0-9_-]{1,20}$"},"scope":{"description":"Use roofline_only for A or roofline_ridges_front_gable for B. roofline_trees_bushes is accepted only for compatibility with older callers; new requests use the separate landscape object.","enum":["roofline_only","roofline_ridges_front_gable","roofline_trees_bushes"]}}}},"landscape":{"type":"object","additionalProperties":false,"required":["trees","bushes"],"properties":{"trees":{"type":"boolean"},"bushes":{"type":"boolean"}},"description":"Optional tree and bush requests applied to each selected option."},"questions":{"type":"array","uniqueItems":true,"maxItems":6,"description":"Optional question categories; standard service answers are included in the 202 response.","items":{"enum":["purchase_or_lease","installation_dates","takedown_dates","storage","warranty","in_season_service"]}},"communication":{"type":"object","additionalProperties":false,"required":["channel","allowCalls","allowSms"],"properties":{"channel":{"const":"email"},"allowCalls":{"const":false},"allowSms":{"const":false}}},"authorization":{"type":"object","additionalProperties":false,"required":["authorizedToRequestQuote"],"properties":{"authorizedToRequestQuote":{"const":true}}},"notes":{"type":"string","minLength":1,"maxLength":2000}}},"example":{"schemaVersion":"1","customer":{"name":"Example Customer","replyEmail":"customer@example.com"},"property":{"addressLine1":"123 Example Lane","city":"Raleigh","state":"NC","postalCode":"27615"},"options":[{"id":"A","scope":"roofline_only"},{"id":"B","scope":"roofline_ridges_front_gable"}],"landscape":{"trees":true,"bushes":true},"communication":{"channel":"email","allowCalls":false,"allowSms":false},"authorization":{"authorizedToRequestQuote":true},"notes":"Please consider the selected roofline and landscaping scopes."}}}},"responses":{"200":{"description":"No job was started because the address is outside the service area or is an individual apartment unit. status is OUT_OF_SERVICE_AREA or APARTMENT_UNIT, jobId is null and message is safe to relay to the customer. No quote will be produced and nobody follows up. Do not resubmit the same address.","content":{"application/json":{"schema":{"type":"object","required":["requestId","jobId","status","message"],"properties":{"requestId":{"type":"string"},"jobId":{"type":"null"},"status":{"enum":["OUT_OF_SERVICE_AREA","APARTMENT_UNIT"]},"message":{"type":"string"},"servicePolicies":{"type":"object"}}}}}},"202":{"description":"The existing quote workflow accepted the job. It may still be processing. New responses include shared servicePolicies; older responses may omit them. The status field is the job status at submission. ACQUIRING_SOURCES: the quote is being generated, so open quoteUrl and tell the customer it will be emailed. SOURCE_UNAVAILABLE or SOLAR_DATA_ERROR: there will be NO automatic quote for this address (satellite measurement is unavailable); Jolly Raleigh staff were alerted and will review it by hand. Tell the customer there is no instant quote, the team will review the request, and they will be emailed only if it can be quoted. Do not promise a quote, a call, or a time. Do not resubmit. After submission the quote page can also show NEEDS_REVIEW or ANALYSIS_DEGRADED (a person is reviewing, same guidance) or AWAITING_CUSTOMER_PHOTO (the team may ask for a photo by email). Only READY means a quote exists.","content":{"application/json":{"example":{"requestId":"example-request-id","jobId":"example-job-id","publicToken":"<keep-private>","quoteUrl":"/property/example-job-id?t=<keep-private>","status":"ACQUIRING_SOURCES","servicePolicies":{"lights":"Lights are leased.","storage":"Storage is included.","installation":"Available installation weeks are shown at checkout. Choose an available week; we guarantee installation during that week.","takedown":"Takedown scheduling is dynamic. We guarantee takedown by January 21.","service":"Lights that are out are repaired within 48 hours at no extra charge.","policyUrl":"https://jollyraleigh.com/christmas-lights/"}},"schema":{"type":"object","required":["requestId","jobId","publicToken","quoteUrl","status"],"properties":{"requestId":{"type":"string"},"jobId":{"type":"string"},"publicToken":{"type":"string"},"quoteUrl":{"type":"string"},"status":{"type":"string"},"servicePolicies":{"description":"Shared service answers; absent on legacy responses.","type":"object","additionalProperties":false,"required":["lights","storage","installation","takedown","service","policyUrl"],"properties":{"lights":{"type":"string"},"storage":{"type":"string"},"installation":{"type":"string"},"takedown":{"type":"string"},"service":{"type":"string"},"policyUrl":{"type":"string","format":"uri"}}}}}}}},"400":{"description":"Invalid JSON or missing/invalid Idempotency-Key.","content":{"application/json":{"schema":{"type":"object","required":["error","requestId"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryAfterSeconds":{"type":"integer","minimum":0}}},"requestId":{"type":"string"}}}}}},"409":{"description":"The key conflicts or the original job outcome is unresolved. Reuse the same key; contact written support if needed.","content":{"application/json":{"schema":{"type":"object","required":["error","requestId"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryAfterSeconds":{"type":"integer","minimum":0}}},"requestId":{"type":"string"}}}}}},"413":{"description":"Request body exceeds 16 KiB.","content":{"application/json":{"schema":{"type":"object","required":["error","requestId"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryAfterSeconds":{"type":"integer","minimum":0}}},"requestId":{"type":"string"}}}}}},"415":{"description":"Content-Type must be application/json.","content":{"application/json":{"schema":{"type":"object","required":["error","requestId"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryAfterSeconds":{"type":"integer","minimum":0}}},"requestId":{"type":"string"}}}}}},"422":{"description":"Request fields do not match the v1 schema.","content":{"application/json":{"schema":{"type":"object","required":["error","requestId"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryAfterSeconds":{"type":"integer","minimum":0}}},"requestId":{"type":"string"}}}}}},"429":{"description":"A request limit was reached; honor Retry-After.","content":{"application/json":{"schema":{"type":"object","required":["error","requestId"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryAfterSeconds":{"type":"integer","minimum":0}}},"requestId":{"type":"string"}}}}}},"503":{"description":"Intake or a required dependency is unavailable; honor Retry-After.","content":{"application/json":{"schema":{"type":"object","required":["error","requestId"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"retryAfterSeconds":{"type":"integer","minimum":0}}},"requestId":{"type":"string"}}}}}}}}}}}