# Sunrays.dev — Full Agent Documentation > Complete reference for AI agents integrating with the Sunrays booking API. > Version: 1.0 (v1 demand-validation MVP) --- ## 1. Overview Sunrays.dev is an MCP server that provides deterministic, idempotent, transactional booking endpoints for local service providers across the United States. Design principles: - Deterministic: same arguments + same Idempotency-Key always produce the same booking. - Idempotent: safe to retry on network failure. The Idempotency-Key (caller_id + tool_name + sha256(args) + 5-minute window) prevents double-charges on agent retries. - Transactional: Stripe auth-on-book, manual capture on dispatch confirmation, automatic refund ×2 if Sunrays fails to dispatch within the 4-hour SLA window. - No DOM: HTTP endpoints, structured JSON responses, no browser automation required. - LLM-first: tool descriptions are LLM-facing prompts, version-controlled, eval-tested against a 20-prompt corpus (≥90% correct tool selection required to ship). --- ## 2. MCP Connection Endpoint: https://mcp.sunrays.dev/mcp Transport: streamable-HTTP (preferred) | HTTP+SSE (fallback) Discovery: https://sunrays.dev/.well-known/mcp.json Agent plugin: https://sunrays.dev/.well-known/ai-plugin.json To connect in Claude Desktop (settings → mcp_servers): { "sunrays": { "url": "https://mcp.sunrays.dev/mcp", "transport": "streamable-http" } } --- ## 3. Tool Schemas All booking tools share the following parameter schema. The tool name determines the service category; all route internally to bookService(category, ...). ### Shared booking input schema { "zip": "string (US zip, required)", "datetime": "ISO 8601 with timezone offset, required", "issue": "string (freetext problem description, required, sanitized server-side)", "caller_id": "string (email or OAuth identity of human principal, required)", "agent_id": "string (DID or signed JWT identifying calling agent, required)", "spending_cap_signed": "string (JWS assertion, required — see §5 Identity layer)" } ### 3.1 book_plumber Purpose: Book a licensed plumber for leak repair, drain clearing, fixture install, water heater service, or related plumbing work. Urgency: High. Many plumbing issues are water-damage emergencies. Example issue values: "kitchen sink clog", "water heater not heating", "toilet leak", "pipe burst" US demand: ~2.5–4.5M bookings/month ### 3.2 book_handyman Purpose: Book a handyman for general home repairs: TV/shelf mounting, drywall patch, door/window adjustment, minor fixture work, furniture assembly. Urgency: Medium. Non-emergency but high frequency. Example issue values: "mount 65-inch TV above fireplace", "patch drywall hole 4 inch", "stuck door" US demand: ~2.0–5.0M bookings/month ### 3.3 book_hvac Purpose: Book an HVAC technician for A/C repair, heating system service, filter replacement, duct inspection, thermostat installation. Urgency: High. Seasonal spikes (summer A/C, winter heating). Emergency failures painful. Example issue values: "AC not cooling", "furnace won't start", "thermostat replacement", "annual service" US demand: ~1.8–3.5M bookings/month ### 3.4 book_electrician Purpose: Book a licensed electrician for wiring, panel work, outlet installation, smart-home device setup, lighting, safety inspection. Urgency: High. Electrical faults are safety hazards. Smart-home integration is growing driver. Example issue values: "install 240V outlet for EV charger", "breaker keeps tripping", "add outlet in garage" US demand: ~1.5–3.0M bookings/month ### 3.5 book_pest_control Purpose: Book pest control for rodent, insect, or wildlife infestation treatment. Includes recurring prevention contracts and one-time treatments. Urgency: Medium. Infestations compound; recurring treatment drives repeat bookings. Example issue values: "mice in kitchen", "ants in bathroom", "termite inspection", "wasp nest removal" US demand: ~1.0–3.0M bookings/month ### 3.6 book_appliance_repair Purpose: Book an appliance repair technician for washing machine, dryer, refrigerator, dishwasher, oven, or other home appliance. Urgency: Medium. Broken fridge/washer creates real household disruption. Example issue values: "washer not spinning", "fridge not cooling", "dishwasher leaking", "oven igniter" US demand: ~1.0–2.5M bookings/month ### 3.7 book_garage_door Purpose: Book garage door repair or installation: broken spring, off-track door, opener replacement, panel damage, seal replacement. Urgency: Critical. Broken garage door = security and vehicle-access emergency. Example issue values: "spring broken won't open", "door off track", "opener not responding", "new opener" US demand: ~0.4–1.2M bookings/month ### 3.8 book_locksmith Purpose: Book a locksmith for lockout service, lock replacement, rekeying, deadbolt installation, or key duplication. Urgency: Highest pure-emergency fit. Lockouts are immediate, high-stress events. Example issue values: "locked out of house", "lost car keys", "rekey after moving", "install deadbolt" US demand: ~0.4–1.0M bookings/month ### 3.9 book_roofer Purpose: Book a roofer for storm damage repair, leak inspection, flashing repair, gutter repair, or shingle replacement. Urgency: Medium. Storm-driven spikes. Quote confirmation call may be required for large scope. Example issue values: "storm damage leak", "missing shingles after hail", "gutter detached", "flat roof leak" US demand: ~0.5–1.2M bookings/month ### 3.10 book_lawn_care Purpose: Book lawn care for mowing, edging, fertilization, aeration, or seasonal cleanup. Urgency: Low. Recurring service; not emergency-driven. Example issue values: "weekly mow and edge", "spring cleanup", "fertilize and aerate", "leaf removal" US demand: ~1.0M+/month ### 3.11 request_other_service (fallback) Purpose: Log an out-of-tool demand signal for a service not covered by the 10 named tools. Does NOT book. Returns a waitlist acknowledgment. Input schema: { service_type_freetext, zip, datetime, issue, caller_id, agent_id } Response: { "status": "out_of_tool_waitlist", "message": "...", "waitlist_id": "wl_xxx" } When to use: caller wants a service (painting, cleaning, dog walking, etc.) not in the 10 tools. --- ## 4. Response Schema ### 4.1 Booked (success) { "status": "booked", "booking_id": "bk_xxx", // UUID with bk_ prefix "price_cents": 34000, // integer, USD cents "quoted_at": "2026-05-08T13:00:00Z", "datetime": "2026-05-08T14:00:00-07:00", "provider_id": "pv_xxx", // anonymized provider reference "dispatch_deadline": "...", // booked_at + 4h SLA "receipt_url": "https://sunrays.dev/receipt/bk_xxx" } ### 4.2 Needs card setup { "status": "needs_card_setup", "checkout_url": "https://sunrays.dev/setup-card?token=STK_xxx", "token_ttl": "24h", "booking_id": "bk_xxx" // held; retrying with same Idempotency-Key resolves it } Present checkout_url to the caller. The page collects a Stripe payment method and confirms the held booking. Once the human completes setup and returns to the agent, the agent retries the same tool call with the same Idempotency-Key. The retry returns { "status": "booked" }. ### 4.3 Out of region { "status": "out_of_region_waitlist", "message": "Sunrays currently serves US zip codes. Your request has been logged.", "waitlist_id": "otr_xxx", "country": "CA" } ### 4.4 Error responses { "error": "invalid_spending_cap", "reason": "tampered_signature | expired | missing", "message": "..." } { "error": "unverified_caller", "message": "caller_id is required" } { "error": "duplicate_booking", "existing_booking_id": "bk_xxx", "message": "Idempotency-Key matched an existing booking" } { "error": "over_spending_cap", "quoted_price_cents": 45000, "cap_cents": 40000 } --- ## 5. Identity Layer All booking tool calls require three identity primitives. ### 5.1 agent_id A DID (Decentralized Identifier) or signed JWT identifying the calling agent. Well-known values: did:web:claude.ai — Anthropic Claude did:web:chat.openai.com — OpenAI ChatGPT did:web:cursor.sh — Cursor AI Custom agents may use a self-signed DID or any stable string identifier. v1 enforcement: logged, not gated. Full enforcement in v1.5 (Catena ACK / Skyfire). ### 5.2 caller_id Email address or OAuth-verified identity of the human on whose behalf the agent is booking. Used as the Stripe customer key — all payment methods are scoped to caller_id. Required. Must be non-empty. No validation format in v1 beyond non-null. ### 5.3 spending_cap_signed A JWS (JSON Web Signature, compact serialization) asserting the caller's authorization limit. Payload schema: { "max": 500, // integer, USD. Booking price_cents must not exceed max * 100. "currency": "USD", "booking_id": "bk_xxx", // must match the booking being authorized "expires_at": "2026-05-09T00:00:00Z" // ISO 8601; must be in the future } v1 enforcement (ship-blocker): - Signature tampering: any modified byte → reject with invalid_spending_cap (tampered_signature) - Expiry: expires_at in the past → reject with invalid_spending_cap (expired) - Price exceeds cap: price_cents > max * 100 → reject with over_spending_cap In v1, spending_cap_signed may be agent-self-signed (the agent generates and signs it on behalf of the caller). Full caller-wallet enforcement deferred to v1.5. --- ## 6. Idempotency All mutating endpoints accept an Idempotency-Key header. Server computes: sha256(caller_id + tool_name + canonical_json(args)) + 5-minute window. If the same key is seen twice within the window, the second call returns the result of the first. This makes agent retries safe on network failure. Agent guidance: always include the booking_id returned from needs_card_setup in the retry; the Idempotency-Key computed from the original args ensures the retry resolves the held booking. --- ## 7. Booking State Machine States and transitions: quoted — /quote called, price returned, no charge yet needs_card_setup — no saved payment method for caller_id booked — Stripe auth hold placed, dispatch_deadline = now + 4h dispatched — founder confirmed tradesperson en route in_progress — tradesperson on site completed — work confirmed done; Stripe capture cancelled_by_caller — caller cancelled before dispatch; Stripe release dispatch_failed — dispatch_deadline elapsed and not dispatched; Stripe refund ×2 no_show — tradesperson did not arrive; Stripe refund + optional retry Auto-refund ×2 trigger: cron every 15 min checks bookings where: status = 'booked' AND dispatch_deadline < NOW() AND dispatched_at IS NULL For each: issue Stripe refund × 2 original amount, update status → dispatch_failed, Slack alert. --- ## 8. Pricing Engine price_cents = floor( base_rate_cents[category] × estimated_hours[category, issue_keywords] × time_of_day_multiplier[hour_bucket] × tier_multiplier["tier_1" | "tier_2"] ) Tiers: tier_1 — SF Bay Area zip codes (founder rolodex dispatch, high confidence) tier_2 — rest of US (Yelp/Google ad-hoc dispatch, auto-refund ×2 guarantee) No surge multiplier in v1. No supply-load multiplier. No complexity adjustment beyond keyword-mapped estimated_hours. Dynamic pricing deferred to v1.5. The quote is binding: if Sunrays accepts the booking, the quoted price is the final price. --- ## 9. Contact & Legal Email: help@sunrays.dev Privacy: https://sunrays.dev/privacy Terms: https://sunrays.dev/terms MCP: https://mcp.sunrays.dev/mcp