{"openapi":"3.0.0","info":{"title":"ActuallyCare API","version":"1.0.0","description":"# AI-Ready REST API for Real Estate Transaction Management\n\nThis API provides comprehensive endpoints for managing real estate transactions, including:\n- **Escrows**: Complete transaction lifecycle management\n- **Listings**: Property inventory and marketing\n- **Clients**: Contact and relationship management\n- **Appointments**: Calendar and scheduling\n- **Leads**: Lead qualification and conversion pipeline\n\n## AI Integration\nThis API is fully compatible with:\n- Anthropic Claude (Sonnet 4.6, Opus 4.6, Haiku 4.5)\n- Anthropic Claude MCP (Model Context Protocol)\n- Custom AI agents and automation\n\n## Authentication\nAll endpoints require authentication via:\n- JWT Bearer tokens (for user sessions)\n- API Keys (for external integrations and AI agents)","contact":{"name":"ActuallyCare Support","email":"support@actuallycare.com","url":"https://www.actuallycare.com"},"license":{"name":"Proprietary","url":"https://www.actuallycare.com/legal"}},"servers":[{"url":"https://api.actuallycare.com/v1","description":"Production server"},{"url":"http://localhost:3001/v1","description":"Development server"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token obtained from /auth/login endpoint"},"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key for external integrations and AI agents"}},"responses":{"UnauthorizedError":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"object","properties":{"code":{"type":"string","example":"NO_AUTH_TOKEN"},"message":{"type":"string","example":"No authentication token provided"}}}}}}}},"NotFoundError":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"object","properties":{"code":{"type":"string","example":"NOT_FOUND"},"message":{"type":"string","example":"Resource not found"}}}}}}}},"ValidationError":{"description":"Invalid request data","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"object","properties":{"code":{"type":"string","example":"VALIDATION_ERROR"},"message":{"type":"string","example":"Invalid request data"},"details":{"type":"array","items":{"type":"string"}}}}}}}}},"ServerError":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"INTERNAL_ERROR","message":"An internal error occurred","errorId":"ERR_1782972632_k4n9qz","correlationId":"6a1d94e7-2c8b-4f53-a0e9-7b3c5d218f64"},"timestamp":"2026-07-01T22:41:12.408Z"}}}},"RateLimitError":{"description":"Rate limit exceeded — too many requests in the current window. Wait for the window to reset (see Retry-After) before retrying.","headers":{"Retry-After":{"description":"Seconds until the current rate-limit window resets and requests will be accepted again","schema":{"type":"integer","example":900}},"RateLimit-Limit":{"description":"Request ceiling for the current window","schema":{"type":"integer","example":500}},"RateLimit-Remaining":{"description":"Requests remaining in the current window","schema":{"type":"integer","example":0}},"RateLimit-Reset":{"description":"Seconds until the current window resets","schema":{"type":"integer","example":512}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"RATE_LIMIT_EXCEEDED","message":"Too many requests from this IP, please try again later.","errorId":"3f2b8c14-9d6e-4a71-b5c2-e8f0a1d47c96"}}}}}},"parameters":{"pageParam":{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Page number for pagination"},"limitParam":{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Number of items per page (default 25; GET /escrows overrides this to 20 at the controller level)"},"idParam":{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Unique identifier (UUID)"}},"schemas":{"PublicPlan":{"type":"object","properties":{"key":{"type":"string","enum":["agent","team","broker"]},"name":{"type":"string","example":"ActuallyCare+ Agent"},"priceMonthly":{"type":"integer","description":"Monthly price in cents","example":10000},"priceYearly":{"type":"integer","description":"Yearly price in cents","example":120000},"trialDays":{"type":"integer","example":30},"seats":{"type":"integer","example":1},"features":{"type":"array","items":{"type":"string"}}}},"Contact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"first_name":{"type":"string"},"last_name":{"type":"string"},"full_name":{"type":"string","description":"Generated from first and last name (read-only)"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"contact_type":{"type":"string","enum":["buyer","seller","agent","lender","title_officer","inspector","appraiser","contractor","client","vendor","other"]},"contact_status":{"type":"string"},"company":{"type":"string"},"license_number":{"type":"string"},"street_address":{"type":"string"},"city":{"type":"string"},"state":{"type":"string","description":"Two-letter state code"},"zip_code":{"type":"string"},"notes":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"is_archived":{"type":"boolean"},"archived_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Escrow":{"type":"object","description":"Real estate transaction (escrow) record","required":["property_address"],"properties":{"id":{"type":"string","format":"uuid","description":"Unique identifier","example":"550e8400-e29b-41d4-a716-446655440000"},"user_id":{"type":"string","format":"uuid","description":"Owner/agent ID"},"property_address":{"type":"string","description":"Full property address","example":"123 Main St, Tehachapi, CA 93561"},"city":{"type":"string","description":"City name","example":"Tehachapi"},"state":{"type":"string","description":"State abbreviation","example":"CA"},"zip_code":{"type":"string","description":"ZIP code","example":"93561"},"purchase_price":{"type":"number","format":"double","minimum":0,"description":"Purchase price in USD","example":500000},"escrow_status":{"type":"string","enum":["active","pending","closed","cancelled"],"description":"Current status","example":"active"},"acceptance_date":{"type":"string","format":"date","description":"Offer acceptance date","example":"2025-01-15"},"closing_date":{"type":"string","format":"date","description":"Expected closing date","example":"2025-03-01"},"buyers":{"type":"array","description":"List of buyers","items":{"$ref":"#/components/schemas/Person"}},"sellers":{"type":"array","description":"List of sellers","items":{"$ref":"#/components/schemas/Person"}},"listing_agent":{"$ref":"#/components/schemas/Agent"},"selling_agent":{"$ref":"#/components/schemas/Agent"},"escrow_company":{"type":"string","description":"Escrow/title company name","example":"First American Title"},"escrow_officer":{"type":"string","description":"Escrow officer name","example":"Jane Smith"},"property_type":{"type":"string","enum":["single_family","condo","townhouse","multi_family","land","commercial"],"example":"single_family"},"bedrooms":{"type":"integer","minimum":0,"example":3},"bathrooms":{"type":"number","format":"float","minimum":0,"example":2.5},"square_feet":{"type":"integer","minimum":0,"example":2400},"lot_size":{"type":"number","format":"float","minimum":0,"description":"Lot size in acres","example":0.25},"year_built":{"type":"integer","minimum":1800,"maximum":2100,"example":2015},"contingencies":{"type":"array","description":"Active contingencies","items":{"type":"object","properties":{"type":{"type":"string","example":"inspection"},"due_date":{"type":"string","format":"date"},"status":{"type":"string","enum":["pending","satisfied","waived","removed"]}}}},"earnest_money":{"type":"number","format":"double","minimum":0,"description":"Earnest money deposit amount","example":10000},"commission_rate":{"type":"number","format":"float","minimum":0,"maximum":100,"description":"Commission percentage","example":3},"notes":{"type":"string","description":"Internal notes"},"version":{"type":"integer","description":"Optimistic locking version","example":1},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"last_modified_by":{"type":"string","format":"uuid","description":"Last user to modify record"}}},"Listing":{"type":"object","description":"Property listing record","required":["address","list_price"],"properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"mls_number":{"type":"string","description":"MLS listing number","example":"ML123456"},"address":{"type":"string","example":"456 Oak Ave, Tehachapi, CA 93561"},"city":{"type":"string","example":"Tehachapi"},"state":{"type":"string","example":"CA"},"zip_code":{"type":"string","example":"93561"},"list_price":{"type":"number","format":"double","minimum":0,"example":425000},"status":{"type":"string","enum":["active","pending","sold","withdrawn","expired"],"example":"active"},"property_type":{"type":"string","enum":["single_family","condo","townhouse","multi_family","land","commercial"],"example":"single_family"},"bedrooms":{"type":"integer","minimum":0,"example":4},"bathrooms":{"type":"number","format":"float","minimum":0,"example":3},"square_feet":{"type":"integer","minimum":0,"example":2800},"lot_size":{"type":"number","format":"float","minimum":0,"example":0.5},"year_built":{"type":"integer","example":2010},"description":{"type":"string","description":"Property description"},"listing_date":{"type":"string","format":"date"},"expiration_date":{"type":"string","format":"date"},"photos":{"type":"array","items":{"type":"string","format":"uri"}},"virtual_tour_url":{"type":"string","format":"uri"},"showing_instructions":{"type":"string"},"days_on_market":{"type":"integer","minimum":0},"price_per_sqft":{"type":"number","format":"float"},"version":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Client":{"type":"object","description":"Client/contact record","required":["first_name","last_name","client_type"],"properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"first_name":{"type":"string","example":"John"},"last_name":{"type":"string","example":"Doe"},"email":{"type":"string","format":"email","example":"john.doe@example.com"},"phone":{"type":"string","example":"(555) 123-4567"},"client_type":{"type":"string","enum":["buyer","seller","both"],"example":"buyer"},"status":{"type":"string","enum":["active","inactive","closed"],"example":"active"},"source":{"type":"string","description":"Lead source","example":"Zillow"},"budget_min":{"type":"number","format":"double","minimum":0},"budget_max":{"type":"number","format":"double","minimum":0},"preferred_locations":{"type":"array","items":{"type":"string"}},"property_preferences":{"type":"object","properties":{"bedrooms_min":{"type":"integer"},"bathrooms_min":{"type":"number","format":"float"},"square_feet_min":{"type":"integer"},"property_types":{"type":"array","items":{"type":"string"}}}},"pre_approved":{"type":"boolean","description":"Pre-approved for financing"},"pre_approval_amount":{"type":"number","format":"double"},"notes":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"version":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Appointment":{"type":"object","description":"Calendar appointment/showing","required":["title","start_time","end_time"],"properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"title":{"type":"string","example":"Property Showing - 123 Main St"},"description":{"type":"string"},"appointment_type":{"type":"string","enum":["showing","inspection","signing","meeting","call","other"],"example":"showing"},"start_time":{"type":"string","format":"date-time","example":"2025-02-01T14:00:00Z"},"end_time":{"type":"string","format":"date-time","example":"2025-02-01T15:00:00Z"},"location":{"type":"string","example":"123 Main St, Tehachapi, CA 93561"},"client_id":{"type":"string","format":"uuid"},"listing_id":{"type":"string","format":"uuid"},"escrow_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["scheduled","completed","cancelled","no_show"],"example":"scheduled"},"attendees":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"}}}},"reminder_sent":{"type":"boolean"},"notes":{"type":"string"},"version":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Lead":{"type":"object","description":"Prospective client lead","required":["name"],"properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Jane Smith"},"email":{"type":"string","format":"email","example":"jane.smith@example.com"},"phone":{"type":"string","example":"(555) 987-6543"},"source":{"type":"string","description":"How lead was acquired","example":"Website Form"},"status":{"type":"string","enum":["new","contacted","qualified","unqualified","converted","lost"],"example":"new"},"lead_type":{"type":"string","enum":["buyer","seller","both"],"example":"buyer"},"interest_level":{"type":"string","enum":["hot","warm","cold"],"example":"warm"},"budget":{"type":"number","format":"double"},"timeline":{"type":"string","description":"Expected timeline","example":"3-6 months"},"message":{"type":"string","description":"Initial inquiry message"},"notes":{"type":"string"},"last_contact_date":{"type":"string","format":"date-time"},"next_follow_up":{"type":"string","format":"date-time"},"converted_to_client_id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Person":{"type":"object","properties":{"name":{"type":"string","example":"John Doe"},"email":{"type":"string","format":"email","example":"john@example.com"},"phone":{"type":"string","example":"(555) 123-4567"}}},"Agent":{"type":"object","properties":{"name":{"type":"string","example":"Alex Rivera"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"license":{"type":"string","description":"Real estate license number","example":"DRE #02209852"},"brokerage":{"type":"string","example":"Associated Real Estate"}}},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","description":"Response data (varies by endpoint)"},"timestamp":{"type":"string","format":"date-time"}}},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"object","properties":{"code":{"type":"string","example":"VALIDATION_ERROR"},"message":{"type":"string","example":"Invalid request data"},"errorId":{"type":"string","description":"Unique identifier for this error occurrence — include it in support requests","example":"ERR_1782972632_ab12cd"},"correlationId":{"type":"string","format":"uuid","description":"Request correlation ID for tracing this request through logs","example":"b7e4c2a8-3f6d-4e29-9c41-8d5a2f7e1b93"},"details":{"description":"Present only on operational errors that attach extra detail — omitted otherwise. Shape varies by error: an array of per-field failures for validation errors, an object for others (e.g. { locked_until } on ACCOUNT_LOCKED)."}}},"timestamp":{"type":"string","format":"date-time"}}},"PaginationMeta":{"type":"object","description":"Pagination metadata for list endpoints. List responses nest this object as `data.meta`, alongside the resource array keyed by the resource name (e.g. `data.escrows`, `data.contacts`, `data.leads`).\n","properties":{"page":{"type":"integer","description":"Current page number (1-based)","example":1},"limit":{"type":"integer","description":"Items per page","example":25},"total":{"type":"integer","description":"Total matching records across all pages","example":231},"totalPages":{"type":"integer","description":"Total number of pages","example":10},"hasMore":{"type":"boolean","description":"True when more pages exist after the current one","example":true}}},"Webhook":{"type":"object","properties":{"id":{"type":"string","description":"Webhook ID (wh_ prefix followed by 12 characters)","example":"wh_abc123def456"},"url":{"type":"string","format":"uri","description":"Endpoint that receives event deliveries"},"events":{"type":"array","description":"Subscribed event names (entity.action format)","items":{"type":"string","example":"escrow.created"}},"secret":{"type":"string","description":"Shared secret used to sign deliveries (minimum 10 characters)"},"active":{"type":"boolean"},"last_triggered":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"}}}},"x-business-rules":{"escrows":{"description":"Rules for real estate transaction management","rules":[{"id":"escrow-address-required","field":"property_address","rule":"Property address is mandatory for all escrows","severity":"error"},{"id":"escrow-future-closing","field":"closing_date","rule":"Closing date must be in the future when creating new escrow","severity":"warning","exception":"Can set past date for historical imports"},{"id":"escrow-positive-price","field":"purchase_price","rule":"Purchase price must be positive if provided","severity":"error","validation":"purchase_price > 0"},{"id":"escrow-address-immutable","field":"property_address","rule":"Property address cannot be changed after escrow creation","severity":"error","applies_to":["update"]},{"id":"escrow-status-transitions","field":"escrow_status","rule":"Valid status transitions are pending→active→closed or pending→cancelled","severity":"error","valid_transitions":{"pending":["active","cancelled"],"active":["closed","cancelled"],"closed":[],"cancelled":[]}},{"id":"escrow-price-documentation","field":"purchase_price","rule":"Price changes should be documented in notes or audit log","severity":"warning","applies_to":["update"]},{"id":"escrow-broker-approval","field":"closing_date","rule":"Closing date changes may require broker approval","severity":"warning","applies_to":["update"],"context":"Changes affecting timeline should notify broker"},{"id":"escrow-archive-before-delete","rule":"Only archived escrows can be permanently deleted","severity":"error","applies_to":["delete"]},{"id":"escrow-contingency-dates","field":"contingencies","rule":"Contingency removal dates must be before closing date","severity":"warning"},{"id":"escrow-earnest-money","field":"earnest_money_amount","rule":"Earnest money typically 1-3% of purchase price","severity":"info","validation":"earnest_money_amount between (purchase_price * 0.01) and (purchase_price * 0.03)"}]},"listings":{"description":"Rules for property listing management","rules":[{"id":"listing-address-required","field":"address","rule":"Property address is mandatory","severity":"error"},{"id":"listing-price-required","field":"list_price","rule":"List price must be provided","severity":"error"},{"id":"listing-positive-price","field":"list_price","rule":"List price must be positive","severity":"error","validation":"list_price > 0"},{"id":"listing-future-expiration","field":"expiration_date","rule":"Expiration date must be in the future","severity":"warning"},{"id":"listing-reasonable-bedrooms","field":"bedrooms","rule":"Bedrooms should be between 0 and 20","severity":"warning","validation":"bedrooms >= 0 AND bedrooms <= 20"},{"id":"listing-reasonable-bathrooms","field":"bathrooms","rule":"Bathrooms should be between 0 and 15","severity":"warning","validation":"bathrooms >= 0 AND bathrooms <= 15"},{"id":"listing-positive-sqft","field":"square_feet","rule":"Square footage must be positive if provided","severity":"error","validation":"square_feet > 0"},{"id":"listing-status-transitions","field":"status","rule":"Valid status transitions are active→pending→sold or active→withdrawn/expired","severity":"error","valid_transitions":{"active":["pending","withdrawn","expired"],"pending":["sold","active"],"sold":[],"withdrawn":["active"],"expired":["active"]}},{"id":"listing-mls-sync","field":"mls_number","rule":"MLS number should match Multiple Listing Service records","severity":"warning","context":"Validate against MLS database if integrated"}]},"clients":{"description":"Rules for client contact management","rules":[{"id":"client-name-required","field":"first_name, last_name","rule":"Client must have at least first name or last name","severity":"error"},{"id":"client-contact-method","field":"email, phone","rule":"Client must have at least one contact method (email or phone)","severity":"warning"},{"id":"client-valid-email","field":"email","rule":"Email must be valid format if provided","severity":"error","validation":"Valid email regex"},{"id":"client-budget-range","field":"budget_min, budget_max","rule":"Minimum budget must be less than maximum budget","severity":"error","validation":"budget_min < budget_max"},{"id":"client-positive-budget","field":"budget_min, budget_max","rule":"Budget values must be positive","severity":"error","validation":"budget_min >= 0 AND budget_max > 0"},{"id":"client-type-required","field":"client_type","rule":"Client type must be specified (buyer, seller, both)","severity":"error","validation":"client_type IN ['buyer', 'seller', 'both']"},{"id":"client-duplicate-check","field":"email, phone","rule":"Check for duplicate clients with same email or phone","severity":"warning","context":"Warn before creating duplicate contacts"}]},"appointments":{"description":"Rules for appointment and showing management","rules":[{"id":"appointment-title-required","field":"title","rule":"Appointment must have a title","severity":"error"},{"id":"appointment-time-required","field":"start_time, end_time","rule":"Start and end times are required","severity":"error"},{"id":"appointment-end-after-start","field":"start_time, end_time","rule":"End time must be after start time","severity":"error","validation":"end_time > start_time"},{"id":"appointment-reasonable-duration","field":"start_time, end_time","rule":"Appointment duration should be between 15 minutes and 8 hours","severity":"warning","validation":"duration BETWEEN 15 minutes AND 8 hours"},{"id":"appointment-future-time","field":"start_time","rule":"Appointments should be scheduled in the future","severity":"warning","exception":"Can create past appointments for records"},{"id":"appointment-business-hours","field":"start_time","rule":"Showings typically during business hours (8 AM - 8 PM)","severity":"info","context":"Warn for appointments outside typical hours"},{"id":"appointment-status-transitions","field":"status","rule":"Valid status transitions are scheduled→completed/cancelled/no_show","severity":"error","valid_transitions":{"scheduled":["completed","cancelled","no_show"],"completed":[],"cancelled":[],"no_show":[]}}]},"leads":{"description":"Rules for lead qualification and management","rules":[{"id":"lead-name-required","field":"name","rule":"Lead must have a name","severity":"error"},{"id":"lead-contact-method","field":"email, phone","rule":"Lead must have at least one contact method","severity":"warning"},{"id":"lead-source-tracking","field":"source","rule":"Lead source should be tracked for marketing analytics","severity":"warning","context":"Important for ROI calculation"},{"id":"lead-status-progression","field":"status","rule":"Leads should progress through stages new→contacted→qualified→converted","severity":"info","valid_transitions":{"new":["contacted","unqualified","lost"],"contacted":["qualified","unqualified","lost"],"qualified":["converted","lost"],"unqualified":["contacted"],"converted":[],"lost":["contacted"]}},{"id":"lead-interest-level","field":"interest_level","rule":"Interest level helps prioritize follow-up (hot > warm > cold)","severity":"info","validation":"interest_level IN ['hot', 'warm', 'cold']"},{"id":"lead-conversion-creates-client","rule":"Converting a lead should create a corresponding client record","severity":"error","applies_to":["convert"],"context":"Use /leads/{id}/convert endpoint"}]},"general":{"description":"Cross-entity business rules","rules":[{"id":"california-compliance","rule":"All transactions must comply with California DRE regulations","severity":"info","context":"Broker license 01910265, Officer Josh Riley 01365477"},{"id":"data-retention","rule":"Transaction records must be retained for 3 years minimum","severity":"info","context":"California DRE requirement"},{"id":"audit-trail","rule":"All modifications should maintain audit trail","severity":"info","context":"Optimistic locking version field tracks changes"},{"id":"user-data-isolation","rule":"Users can only access their own data or team data","severity":"error","context":"Enforced by user_id filtering in all queries"},{"id":"price-formatting","rule":"Prices should be stored as numbers, formatted as currency for display","severity":"info","context":"Use toLocaleString('en-US', {style:'currency', currency:'USD'})"},{"id":"date-formatting","rule":"Dates stored as ISO 8601 format (YYYY-MM-DD)","severity":"info","context":"Use YYYY-MM-DD for date fields"}]}}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"tags":[{"name":"Authentication","description":"User authentication and session management"},{"name":"Escrows","description":"Real estate transaction management"},{"name":"Listings","description":"Property inventory and marketing"},{"name":"Clients","description":"Contact and relationship management"},{"name":"Appointments","description":"Calendar and scheduling"},{"name":"Leads","description":"Lead qualification and conversion"},{"name":"Contacts","description":"Contact database — people and vendors across all transactions"},{"name":"Webhooks","description":"Outbound webhook subscriptions for event notifications"},{"name":"Billing","description":"Subscription plans, checkout, and billing management"},{"name":"API Keys","description":"API key management for external integrations"},{"name":"AI","description":"AI-powered natural language query interface"},{"name":"Health","description":"System health and monitoring endpoints"}],"x-ai-integration":{"anthropic":{"enabled":true,"models":["claude-opus-4-6","claude-sonnet-4-6","claude-haiku-4-5-20251001"],"tool_use":true,"mcp_server":{"available":true,"location":"apps/mcp/","description":"Standalone MCP server for Claude Desktop integration"},"embeddings":{"provider":"voyage-ai","model":"voyage-3.5-lite","description":"Voyage AI embeddings for semantic search and clustering"}},"considerations":{"rate_limits":"AI endpoints have stricter rate limits (10/min production, 50/min development)","authentication":"Use X-API-Key header for AI agent authentication","best_practices":["Use operationId for function naming consistency","Check x-consequential before write operations","Implement retry logic for rate limit errors","Cache OpenAPI spec locally to reduce fetches"]}},"paths":{"/billing/public-plans":{"get":{"operationId":"getPublicPlans","summary":"Get public plan pricing","description":"Returns the current subscription plans with pricing in cents. This endpoint requires no authentication and is the source of truth for pricing shown on the marketing site. Responses are cacheable (5 minutes in browsers, 1 hour at the CDN edge).","tags":["Billing"],"security":[],"responses":{"200":{"description":"Available plans","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"plans":{"type":"array","items":{"$ref":"#/components/schemas/PublicPlan"}},"currency":{"type":"string","example":"usd"},"version":{"type":"string","description":"Pricing version date"}}}}}}}},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/billing/public-checkout":{"post":{"operationId":"createPublicCheckout","summary":"Start checkout without an account","description":"Creates a Stripe Checkout session for a new customer who doesn't have an account yet. Only the agent plan is available through this endpoint; team and brokerage subscriptions require an account and the authenticated checkout endpoint. Returns the Stripe-hosted checkout URL to redirect the visitor to.","tags":["Billing"],"x-consequential":true,"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Email address for the new customer and Stripe Checkout session"},"planKey":{"type":"string","enum":["agent"],"default":"agent","description":"Subscription plan tier (only agent is available without an account)"},"interval":{"type":"string","enum":["monthly","yearly"],"default":"monthly","description":"Billing interval (defaults to monthly)"}}}}}},"responses":{"200":{"description":"Checkout session created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"url":{"type":"string","description":"Stripe-hosted checkout page to redirect to"},"sessionId":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/billing/plans":{"get":{"operationId":"getBillingPlans","summary":"Get plans with checkout identifiers","description":"Returns the subscription plans for the in-app billing page. Same plans as the public endpoint, plus the identifiers needed to start an authenticated checkout. Prices here are in dollars.","tags":["Billing"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"responses":{"200":{"description":"Available plans","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["agent","team","brokerage"],"example":"agent"},"name":{"type":"string","example":"ActuallyCare+ Agent"},"priceId":{"type":"string","description":"Stripe Price ID for the legacy monthly checkout","example":"price_1QxT4kGH2vSNn8LKcAgentMo"},"priceIds":{"type":"object","properties":{"monthly":{"type":"string","example":"price_1QxT4kGH2vSNn8LKcAgentMo"},"yearly":{"type":"string","example":"price_1QxT5bGH2vSNn8LKcAgentYr"}}},"price":{"type":"number","description":"Legacy alias for priceMonthly (dollars)","example":100},"priceMonthly":{"type":"number","description":"Monthly price in dollars","example":100},"priceYearly":{"type":"number","description":"Annual price in dollars (10× monthly — 2 months free)","example":1000},"seats":{"type":"integer","description":"Included seats (-1 = unlimited)","example":1},"escrowsPerMonth":{"type":"integer","description":"Escrow cap per month (-1 = unlimited)","example":-1},"includes":{"type":"string","example":"base"},"features":{"type":"array","items":{"type":"string"},"example":["1 agent seat","Unlimited data","Base AI included (~20 requests/session)"]}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/billing/subscription":{"get":{"operationId":"getSubscription","summary":"Get current subscription status","description":"Returns the authenticated user's subscription state at each scope (personal, team, brokerage) plus which scope currently provides coverage.","tags":["Billing"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"responses":{"200":{"description":"Subscription status per scope","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"personal":{"type":"object","nullable":true,"properties":{"status":{"type":"string","enum":["active","trialing","canceling","canceled","none"]},"tier":{"type":"string","enum":["agent","team","broker","free"]},"currentPeriodEnd":{"type":"string","format":"date-time","nullable":true},"canceledAt":{"type":"string","format":"date-time","nullable":true}}},"team":{"type":"object","nullable":true,"description":"Same shape as personal"},"brokerage":{"type":"object","nullable":true,"description":"Same shape as personal"},"effective_coverage":{"type":"string","description":"Highest scope with an active or trialing subscription","enum":["brokerage","team","personal","none"]}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/billing/checkout":{"post":{"operationId":"createCheckout","summary":"Start checkout for a subscription","description":"Creates a Stripe Checkout session for the authenticated user at the requested scope. Valid scope and plan combinations are personal+agent, team+team, brokerage+team, and brokerage+broker. Eligibility depends on your role and how your brokerage pays for seats; ineligible requests return 400 with a specific reason.","tags":["Billing"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scope","planKey"],"properties":{"scope":{"type":"string","enum":["personal","team","brokerage"],"description":"Subscription scope the seat applies to (personal, team, or brokerage)"},"planKey":{"type":"string","enum":["agent","team","broker"],"description":"Subscription plan tier to subscribe to"},"interval":{"type":"string","enum":["monthly","yearly"],"default":"monthly","description":"Billing interval (defaults to monthly)"}}}}}},"responses":{"200":{"description":"Checkout session created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"url":{"type":"string","description":"Stripe-hosted checkout page to redirect to"},"sessionId":{"type":"string"}}}}}}}},"400":{"description":"Invalid scope/plan combination or eligibility check failed (the message explains why)"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Team or brokerage not found"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/billing/portal":{"post":{"operationId":"createBillingPortal","summary":"Open the billing portal","description":"Creates a Stripe customer portal session where the user can manage payment methods, view invoices, and change or cancel their subscription. Requires an existing billing account (returns 400 if the user has never subscribed).","tags":["Billing"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"responses":{"200":{"description":"Portal session created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"url":{"type":"string","description":"Stripe-hosted portal page to redirect to"}}}}}}}},"400":{"description":"No billing account found — subscribe to a plan first"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts":{"get":{"operationId":"listContacts","summary":"List contacts","description":"Returns a paginated list of contacts visible to the authenticated user, with aggregate stats by status. Supports fuzzy search across name and email.","tags":["Contacts"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"search","in":"query","description":"Fuzzy search across full name, first name, last name, and email","schema":{"type":"string","maxLength":200}},{"name":"type","in":"query","description":"Filter by contact type","schema":{"type":"string"}},{"name":"archived","in":"query","description":"Show archived contacts instead of active ones","schema":{"type":"boolean","default":false}},{"$ref":"#/components/parameters/pageParam"},{"$ref":"#/components/parameters/limitParam"}],"responses":{"200":{"description":"Paginated contact list with stats","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"contacts":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"stats":{"type":"object","description":"Counts and portfolio totals grouped by contact status"},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"totalPages":{"type":"integer"},"hasMore":{"type":"boolean"}}}}}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createContact","summary":"Create a contact","description":"Adds a contact to the authenticated user's database. First name and contact type are required.","tags":["Contacts"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["first_name","contact_type"],"properties":{"first_name":{"type":"string","maxLength":100,"description":"Contact's first name"},"last_name":{"type":"string","maxLength":100,"description":"Contact's last name"},"contact_type":{"type":"string","enum":["buyer","seller","agent","lender","title_officer","inspector","appraiser","contractor","client","vendor","other"],"description":"Role this contact plays in transactions (e.g. buyer, seller, lender, inspector)"},"email":{"type":"string","format":"email","description":"Contact's email address"},"phone":{"type":"string","description":"Contact's phone number"},"company":{"type":"string","maxLength":200,"description":"Company or organization the contact belongs to"},"license_number":{"type":"string","maxLength":50,"description":"Professional license number (e.g. for agents, lenders, inspectors)"},"street_address":{"type":"string","maxLength":255,"description":"Street address"},"city":{"type":"string","maxLength":100,"description":"City name"},"state":{"type":"string","maxLength":2,"description":"Two-letter state code"},"zip_code":{"type":"string","maxLength":10,"description":"ZIP code"},"notes":{"type":"string","description":"Free-form notes about the contact"},"tags":{"type":"array","items":{"type":"string"},"description":"Free-form labels for grouping and filtering contacts"}}}}}},"responses":{"201":{"description":"Contact created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/search":{"get":{"operationId":"searchContacts","summary":"Search contacts","description":"Searches the authenticated user's contacts by name, email, or role. Returns a flat array (not paginated) capped at the requested limit.","tags":["Contacts"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"name","in":"query","description":"Case-insensitive substring match on full name","schema":{"type":"string","maxLength":200}},{"name":"email","in":"query","description":"Case-insensitive substring match on email","schema":{"type":"string"}},{"name":"role","in":"query","description":"Filter by assigned contact role name","schema":{"type":"string","maxLength":100}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Matching contacts","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"count":{"type":"integer"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}":{"get":{"operationId":"getContact","summary":"Get a contact","tags":["Contacts"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"The contact","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Contact"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"put":{"operationId":"updateContact","summary":"Update a contact","description":"Updates contact fields. All fields are optional; only the fields you send are changed.","tags":["Contacts"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/idParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"first_name":{"type":"string","description":"Contact's first name"},"last_name":{"type":"string","description":"Contact's last name"},"email":{"type":"string","format":"email","description":"Contact's email address"},"phone":{"type":"string","description":"Contact's phone number"},"contact_type":{"type":"string","description":"Role this contact plays in transactions (e.g. buyer, seller, lender, inspector)"},"contact_status":{"type":"string","description":"Workflow status of the contact (free-form, e.g. active, lead, client, past_client)"},"company":{"type":"string","description":"Company or organization the contact belongs to"},"street_address":{"type":"string","description":"Street address"},"city":{"type":"string","description":"City name"},"state":{"type":"string","description":"Two-letter state code"},"zip_code":{"type":"string","description":"ZIP code"},"notes":{"type":"string","description":"Free-form notes about the contact"},"tags":{"type":"array","items":{"type":"string"},"description":"Free-form labels for grouping and filtering contacts"}}}}}},"responses":{"200":{"description":"Contact updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteContact","summary":"Delete a contact","description":"Soft-deletes a contact. Deleted contacts disappear from all lists and searches and cannot be restored; to hide a contact reversibly, use archive instead.","tags":["Contacts"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Contact deleted (response echoes the deleted contact record)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Contact"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Caller lacks permission to delete this contact"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}/archive":{"patch":{"operationId":"archiveContact","summary":"Archive a contact","description":"Hides a contact from default lists. Archived contacts can be listed with `archived=true` and restored at any time.","tags":["Contacts"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Contact archived (response is the updated contact record)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Contact"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/contacts/{id}/restore":{"patch":{"operationId":"restoreContact","summary":"Restore an archived contact","description":"Returns an archived contact to the active list.","tags":["Contacts"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Contact restored (response is the updated contact record)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Contact"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/escrows":{"get":{"operationId":"listEscrows","summary":"List escrows","description":"Returns a paginated list of escrows visible to the authenticated user, with aggregate stats. Supports filtering by status, price range, closing-date range, and free-text search across property address and display ID. Note the effective default page size for this endpoint is 20 (a controller-level override of the platform-wide default of 25).","tags":["Escrows"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"status","in":"query","description":"Filter by escrow status (case-insensitive)","schema":{"type":"string","enum":["active","pending","closed","cancelled"]}},{"name":"search","in":"query","description":"Free-text search across property address and display ID","schema":{"type":"string"}},{"name":"minPrice","in":"query","description":"Minimum purchase price","schema":{"type":"number","minimum":0}},{"name":"maxPrice","in":"query","description":"Maximum purchase price","schema":{"type":"number","minimum":0}},{"name":"closingDateStart","in":"query","description":"Earliest closing date (ISO 8601)","schema":{"type":"string","format":"date"}},{"name":"closingDateEnd","in":"query","description":"Latest closing date (ISO 8601)","schema":{"type":"string","format":"date"}},{"name":"archived","in":"query","description":"Include archived escrows instead of active ones","schema":{"type":"boolean","default":false}},{"name":"sort","in":"query","description":"Sort column","schema":{"type":"string","default":"created_at"}},{"name":"order","in":"query","description":"Sort direction","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}},{"$ref":"#/components/parameters/pageParam"},{"$ref":"#/components/parameters/limitParam"}],"responses":{"200":{"description":"Paginated escrow list with aggregate stats","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"escrows":{"type":"array","items":{"$ref":"#/components/schemas/Escrow"}},"stats":{"type":"object","description":"Aggregate counts, volume, and commission totals by status"},"meta":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"},"hasMore":{"type":"boolean"}}}}}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createEscrow","summary":"Create an escrow","description":"Opens a new escrow (transaction). Only the property address is required; financial, party, and vendor details can be added later.","tags":["Escrows"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["property_address"],"properties":{"property_address":{"type":"string","description":"Street address of the property in escrow"},"purchase_price":{"type":"number","description":"Purchase price in USD"},"escrow_status":{"type":"string","enum":["active","pending","closed","cancelled"],"default":"active","description":"Initial escrow status (defaults to active)"},"acceptance_date":{"type":"string","format":"date","description":"Offer acceptance date (ISO 8601)"},"closing_date":{"type":"string","format":"date","description":"Expected closing date (ISO 8601)"},"city":{"type":"string","description":"City name"},"state":{"type":"string","description":"State abbreviation (e.g. CA)"},"zip_code":{"type":"string","description":"ZIP code"},"earnest_money_deposit":{"type":"number","description":"Earnest money deposit amount in USD"},"commission_percentage":{"type":"number","description":"Total commission rate as a percentage of purchase price"},"my_commission":{"type":"number","description":"The authenticated agent's commission amount in USD"},"representation_type":{"type":"string","description":"Which side the agent represents (e.g. buyer, seller, dual)"},"escrow_company":{"type":"string","description":"Escrow company handling the transaction"},"title_company":{"type":"string","description":"Title company name"},"buyers":{"type":"array","description":"Buyer parties to attach at creation","items":{"type":"object","properties":{"name":{"type":"string","description":"Buyer's full name"},"email":{"type":"string","description":"Buyer's email address"}}}},"sellers":{"type":"array","description":"Seller parties to attach at creation","items":{"type":"object","properties":{"name":{"type":"string","description":"Seller's full name"},"email":{"type":"string","description":"Seller's email address"}}}}}}}}},"responses":{"201":{"description":"Escrow created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","description":"Escrow ID (UUID or display ID)"},"displayId":{"type":"string","description":"Human-readable display ID","example":"ESC-2026-0001"}}}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/escrows/{id}":{"get":{"operationId":"getEscrow","summary":"Get an escrow","description":"Returns a single escrow. The ID may be a UUID, a display ID (ESC-2026-0001), or the user-scoped numeric sequence.","tags":["Escrows"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Escrow UUID, display ID, or numeric sequence","schema":{"type":"string"}}],"responses":{"200":{"description":"The escrow","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Escrow"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"put":{"operationId":"updateEscrow","summary":"Update an escrow","description":"Updates escrow fields. Pass the current `version` to enable optimistic-locking; a stale version returns 409.","tags":["Escrows"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"purchase_price":{"type":"number","description":"Purchase price in USD"},"closing_date":{"type":"string","format":"date","description":"Expected closing date (ISO 8601)"},"escrow_status":{"type":"string","enum":["active","pending","closed","cancelled"],"description":"Updated escrow status"},"version":{"type":"integer","description":"Current record version for optimistic locking"}}}}}},"responses":{"200":{"description":"Escrow updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Escrow"},"message":{"type":"string","example":"Escrow updated successfully"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"409":{"description":"Version conflict (record changed since you read it) or business-rule violation"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteEscrow","summary":"Delete an escrow","description":"Permanently deletes an escrow. The escrow must be archived first (PATCH /escrows/{id}/archive); deleting a non-archived escrow returns 400.","tags":["Escrows"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Escrow deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Escrow permanently deleted"},"data":{"type":"object","properties":{"displayId":{"type":"string","example":"ESC-2026-0847"}}}}}}}},"400":{"description":"Escrow is not archived — archive it before deleting"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/escrows/{id}/archive":{"patch":{"operationId":"archiveEscrow","summary":"Archive an escrow","description":"Moves an escrow to the archive. Archived escrows are hidden from default lists, can be restored at any time, and are the only escrows eligible for permanent deletion.","tags":["Escrows"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Escrow archived","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Escrow archived successfully"},"data":{"type":"object","properties":{"displayId":{"type":"string","example":"ESC-2026-0847"}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/escrows/{id}/restore":{"patch":{"operationId":"restoreEscrow","summary":"Restore an archived escrow","description":"Returns an archived escrow to the active list.","tags":["Escrows"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Escrow restored","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Escrow restored successfully"},"data":{"type":"object","properties":{"displayId":{"type":"string","example":"ESC-2026-0847"}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/escrows/{id}/timeline":{"get":{"operationId":"getEscrowTimeline","summary":"Get an escrow's timeline","description":"Returns the escrow's milestone timeline (deposits, contingencies, closing) with target dates, completion state, and a computed status for each milestone.","tags":["Escrows"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Timeline milestones in display order","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Milestone key (e.g. emd, inspection)"},"label":{"type":"string"},"date":{"type":"string","format":"date-time","nullable":true},"completed":{"type":"boolean"},"completedDate":{"type":"string","format":"date-time","nullable":true},"status":{"type":"string","enum":["active","pending","completed","expired","removed"]},"sortOrder":{"type":"integer"}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/auth/register":{"post":{"operationId":"registerUser","summary":"Register new user","description":"Creates a new user account and always returns a signed JWT.\n\n**Waitlist gate:** when the platform is accepting signups (`ACCEPT_NEW_USERS=true`,\nor the registration arrives via a brokerage invite) the account is created with\nstatus `active` and onboarding starts immediately. Otherwise the account is created\nwith status `waitlisted` — the returned JWT can only reach `/auth/*` and `/waitlist/*`\nendpoints; every other endpoint returns 403 with error.code `ACCOUNT_NOT_ACTIVE`\nuntil an admin approves the account. Both outcomes return 201 with the same shape;\ncheck `data.status` and follow `data.redirect`.\n","tags":["Authentication"],"security":[],"x-consequential":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","username","password","firstName","lastName"],"properties":{"email":{"type":"string","format":"email","description":"User's email address (login identifier, stored lowercase)","example":"sarah.chen@gmail.com"},"username":{"type":"string","pattern":"^[a-zA-Z0-9_]+$","minLength":3,"maxLength":30,"description":"Unique username — letters, numbers, and underscores only (stored lowercase)","example":"sarahchen"},"password":{"type":"string","minLength":8,"description":"Account password — min 8 chars, at least one uppercase letter and one number"},"firstName":{"type":"string","maxLength":100,"description":"User's first name","example":"Sarah"},"lastName":{"type":"string","maxLength":100,"description":"User's last name","example":"Chen"},"role":{"type":"string","enum":["agent","broker","lender","vendor"],"default":"agent","description":"Optional starting role for the account"},"emailKind":{"type":"string","enum":["personal","work","offers"],"description":"Optional classification of the provided email address"},"phone":{"type":"string","description":"Optional phone number (required for SMS consent to be recorded)","example":"(661) 555-0142"},"smsConsent":{"type":"boolean","description":"Optional explicit consent to receive SMS (recorded only when phone is provided)"}}}}}},"responses":{"201":{"description":"User registered — `data.status` is `active` or `waitlisted` depending on the ACCEPT_NEW_USERS gate","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"},"role":{"type":"array","items":{"type":"string"},"description":"Roles array (users.role is a text array, e.g. [\"agent\"])"},"isActive":{"type":"boolean"},"status":{"type":"string","enum":["active","waitlisted"]}}},"token":{"type":"string","description":"Signed JWT — issued for both active and waitlisted accounts"},"status":{"type":"string","enum":["active","waitlisted"]},"redirect":{"type":"string","enum":["/get-started","/waitlist-pending"],"description":"Client-side route to send the new user to"},"onboarding":{"type":"object","nullable":true,"description":"Present only for active accounts; null when waitlisted","properties":{"sampleDataGenerated":{"type":"boolean"},"tutorialAvailable":{"type":"boolean"},"nextStep":{"type":"string"}}}}},"message":{"type":"string"}}},"examples":{"activeSignup":{"summary":"Platform accepting signups (ACCEPT_NEW_USERS=true or invite)","value":{"success":true,"data":{"user":{"id":"b7e9d2c4-5f1a-4e8b-9c3d-2a6f8e0b4d17","email":"sarah.chen@gmail.com","firstName":"Sarah","lastName":"Chen","role":["agent"],"isActive":true,"status":"active"},"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImI3ZTlkMmM0LTVmMWEtNGU4Yi05YzNkLTJhNmY4ZTBiNGQxNyJ9.Qm4x8pT2cVhLk9wYzR0aXNlY3VyZQ","status":"active","redirect":"/get-started","onboarding":{"sampleDataGenerated":true,"tutorialAvailable":true,"nextStep":"/onboarding/welcome"}},"message":"User registered successfully"}},"waitlistedSignup":{"summary":"Waitlist gate closed (ACCEPT_NEW_USERS unset/false)","value":{"success":true,"data":{"user":{"id":"b7e9d2c4-5f1a-4e8b-9c3d-2a6f8e0b4d17","email":"sarah.chen@gmail.com","firstName":"Sarah","lastName":"Chen","role":["agent"],"isActive":true,"status":"waitlisted"},"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImI3ZTlkMmM0LTVmMWEtNGU4Yi05YzNkLTJhNmY4ZTBiNGQxNyJ9.Qm4x8pT2cVhLk9wYzR0aXNlY3VyZQ","status":"waitlisted","redirect":"/waitlist-pending","onboarding":null},"message":"Thanks for signing up — your account is on the waitlist. We will email you when it is approved."}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"409":{"description":"A user with this email or username already exists (case-insensitive check)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"ConflictError","message":"User with this email or username already exists","errorId":"ERR_1782974502113_k4n9qz","correlationId":"0f4a7c2e-9b1d-4e6f-8a3c-5d2b7f9e1c48"},"timestamp":"2026-07-01T22:41:42.113Z"}}}},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/auth/login":{"post":{"operationId":"loginUser","summary":"Login user","description":"Authenticate with email OR username plus password. On full success, returns a JWT\naccess token whose lifetime is role-based (`expiresIn` duration string: `15m` for\nsystem_admin and default, `4h` for broker/team_lead, `8h` for agent) and sets a\n`refreshToken` httpOnly cookie (default 30 days, `JWT_REFRESH_TOKEN_EXPIRY_DAYS`).\n\nThe 200 body has four possible `data` shapes: full login, TOTP challenge\n(`requiresTOTP`), SMS challenge (`requiresSMS`), or waitlisted account.\n","tags":["Authentication"],"security":[],"x-consequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"At least one of email or username is required","required":["password"],"properties":{"email":{"type":"string","example":"sarah.chen@gmail.com","description":"User's email address (provide email OR username; case-insensitive)"},"username":{"type":"string","example":"sarahchen","description":"Username (provide email OR username; case-insensitive)"},"password":{"type":"string","example":"YourPassword123!","description":"Account password"}}}}}},"responses":{"200":{"description":"Password verified — data is one of four shapes (full login, TOTP required, SMS required, waitlisted)","headers":{"Set-Cookie":{"description":"refreshToken httpOnly cookie, set on full login and waitlisted login (not on TOTP/SMS challenge responses). Flags: HttpOnly; Path=/; in production/staging also Secure; SameSite=None; Domain=.actuallycare.com. Max-Age defaults to 30 days (JWT_REFRESH_TOKEN_EXPIRY_DAYS).","schema":{"type":"string","example":"refreshToken=9c2f8e4a1d6b3c5e7f0a2b4d6e8f1a3c; Path=/; HttpOnly; Secure; SameSite=None; Domain=.actuallycare.com; Max-Age=2592000"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"oneOf":[{"title":"Full login","type":"object","required":["user","token","accessToken","expiresIn"],"properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"role":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"},"teamId":{"type":"string","format":"uuid","nullable":true},"teamName":{"type":"string","nullable":true},"brokerageId":{"type":"string","format":"uuid","nullable":true},"corporationName":{"type":"string","nullable":true},"scopeLevel":{"type":"string"},"verticals":{"type":"array","items":{"type":"string"}},"managedTeams":{"type":"array","items":{"type":"object"}}}},"token":{"type":"string","description":"JWT access token"},"accessToken":{"type":"string","description":"Same JWT as token (kept for backward compatibility)"},"refreshToken":{"type":"string","description":"Refresh token (may be absent — cookie creation is non-fatal best-effort)"},"expiresIn":{"type":"string","description":"Role-based access-token lifetime ('15m' system_admin/default, '4h' broker/team_lead, '8h' agent)","example":"8h"},"tokenType":{"type":"string","example":"Bearer"},"requiresTOTPSetup":{"type":"boolean","description":"True for system_admin users who have not yet enabled TOTP"}}},{"title":"TOTP required","type":"object","required":["requiresTOTP","userId"],"properties":{"requiresTOTP":{"type":"boolean","example":true},"userId":{"type":"string","format":"uuid"}}},{"title":"SMS code required","type":"object","required":["requiresSMS","userId"],"description":"SMS 2FA challenge. If the SMS send fails, the endpoint silently falls back to a full login response.","properties":{"requiresSMS":{"type":"boolean","example":true},"userId":{"type":"string","format":"uuid"}}},{"title":"Waitlisted account","type":"object","required":["user","status","redirect"],"description":"Valid credentials on a waitlisted account — token can only reach /auth/* and /waitlist/* until approved","properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"},"status":{"type":"string","example":"waitlisted"}}},"token":{"type":"string"},"accessToken":{"type":"string"},"status":{"type":"string","example":"waitlisted"},"redirect":{"type":"string","example":"/waitlist-pending"}}}]},"message":{"type":"string"}}},"examples":{"fullLogin":{"summary":"Full login (no 2FA, active account)","value":{"success":true,"data":{"user":{"id":"b7e9d2c4-5f1a-4e8b-9c3d-2a6f8e0b4d17","email":"sarah.chen@gmail.com","username":"sarahchen","firstName":"Sarah","lastName":"Chen","role":["agent"],"isActive":true,"teamId":"3c1e8f5a-7d2b-4a9c-b6e4-0f8d2c5a7e91","teamName":"Chen Home Team","brokerageId":"9e4b2d7f-1a6c-4e8b-a3d5-6c0f9b2e4d78","corporationName":"Golden Empire Realty","scopeLevel":"team","verticals":["realtor"],"managedTeams":[]},"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImI3ZTlkMmM0LTVmMWEtNGU4Yi05YzNkLTJhNmY4ZTBiNGQxNyJ9.Qm4x8pT2cVhLk9wYzR0aXNlY3VyZQ","accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImI3ZTlkMmM0LTVmMWEtNGU4Yi05YzNkLTJhNmY4ZTBiNGQxNyJ9.Qm4x8pT2cVhLk9wYzR0aXNlY3VyZQ","refreshToken":"9c2f8e4a1d6b3c5e7f0a2b4d6e8f1a3c5b7d9e0f2a4c6e8b1d3f5a7c9e0b2d4f","expiresIn":"8h","tokenType":"Bearer","requiresTOTPSetup":false},"message":"Login successful"}},"totpRequired":{"summary":"TOTP authenticator challenge","value":{"success":true,"data":{"requiresTOTP":true,"userId":"b7e9d2c4-5f1a-4e8b-9c3d-2a6f8e0b4d17"},"message":"Password verified. Please enter your authenticator code."}},"smsRequired":{"summary":"SMS verification challenge","value":{"success":true,"data":{"requiresSMS":true,"userId":"b7e9d2c4-5f1a-4e8b-9c3d-2a6f8e0b4d17"},"message":"Password verified. A verification code has been sent to your phone."}},"waitlisted":{"summary":"Waitlisted account","value":{"success":true,"data":{"user":{"id":"b7e9d2c4-5f1a-4e8b-9c3d-2a6f8e0b4d17","email":"sarah.chen@gmail.com","firstName":"Sarah","lastName":"Chen","status":"waitlisted"},"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImI3ZTlkMmM0LTVmMWEtNGU4Yi05YzNkLTJhNmY4ZTBiNGQxNyJ9.Qm4x8pT2cVhLk9wYzR0aXNlY3VyZQ","accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImI3ZTlkMmM0LTVmMWEtNGU4Yi05YzNkLTJhNmY4ZTBiNGQxNyJ9.Qm4x8pT2cVhLk9wYzR0aXNlY3VyZQ","status":"waitlisted","redirect":"/waitlist-pending"},"message":"Your account is on the waitlist. We will email you when it is approved."}}}}}},"401":{"description":"Invalid credentials (INVALID_CREDENTIALS) or disabled account (ACCOUNT_DISABLED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"invalidCredentials":{"summary":"Unknown user or wrong password","value":{"success":false,"error":{"code":"INVALID_CREDENTIALS","message":"Invalid username or password","errorId":"ERR_1782974655201_p3x8vq","correlationId":"4b8e2f6a-0c9d-4e1b-8a7f-3d5c1e9b2f60"},"timestamp":"2026-07-01T22:44:15.201Z"}},"accountDisabled":{"summary":"Account deactivated by an admin","value":{"success":false,"error":{"code":"ACCOUNT_DISABLED","message":"Your account has been disabled","errorId":"ERR_1782974702449_m6t1zk","correlationId":"8d2a6c4e-1f7b-4d9a-b0e3-5c8f2a4d6e91"},"timestamp":"2026-07-01T22:45:02.449Z"}}}}}},"403":{"description":"Account suspended (ACCOUNT_SUSPENDED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"ACCOUNT_SUSPENDED","message":"Your account has been suspended. Contact support@actuallycare.com.","errorId":"ERR_1782974733812_q9w4hn","correlationId":"2e6c0a8f-4d1b-4f7e-9c3a-7b5d9e1f3a82"},"timestamp":"2026-07-01T22:45:33.812Z"}}}},"423":{"description":"Account locked (ACCOUNT_LOCKED). The 5th consecutive failed attempt locks the account for 30 minutes; attempts made WHILE locked return this 423 with details.locked_until (the failure that triggers the lock itself returns 401).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"ACCOUNT_LOCKED","message":"Account temporarily locked due to too many failed login attempts. Try again in 27 minutes.","errorId":"ERR_1782974760058_j2r7bd","correlationId":"6a1d94e7-2c8b-4f53-a0e9-7b3c5d218f64","details":{"locked_until":"2026-07-01T23:12:40.058Z"}},"timestamp":"2026-07-01T22:46:00.058Z"}}}},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/auth/refresh":{"post":{"operationId":"refreshAccessToken","summary":"Refresh access token","description":"Exchanges the refresh token (httpOnly `refreshToken` cookie, or `refreshToken` in the request body for cookie-less clients) for a new access token. The refresh token is rotated on every call — the previous one is invalidated and the new one is set on the same httpOnly cookie. A device-fingerprint mismatch (different IP + user agent than the token was issued to) revokes the whole token family and returns 401 FINGERPRINT_MISMATCH.","tags":["Authentication"],"security":[],"x-consequential":false,"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string","description":"Refresh token — only needed when the httpOnly cookie is unavailable (e.g. native clients)"}}}}}},"responses":{"200":{"description":"Token refreshed (a rotated refreshToken cookie is also set)","headers":{"Set-Cookie":{"description":"Rotated httpOnly refreshToken cookie (30-day default expiry)","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"accessToken":{"type":"string","description":"New JWT access token"},"expiresIn":{"type":"string","description":"Access-token lifetime, role-based ('15m' system_admin/default, '4h' broker/team_lead, '8h' agent)","example":"8h"},"refreshTokenExpiresIn":{"type":"string","description":"Lifetime of the rotated refresh token","example":"30d"}}}}}}}},"401":{"description":"Missing, invalid, expired, or revoked refresh token (NO_REFRESH_TOKEN, INVALID_REFRESH_TOKEN, or FINGERPRINT_MISMATCH)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"error":{"code":"INVALID_REFRESH_TOKEN","message":"Invalid or expired refresh token","errorId":"ERR_1782975101447_m3x8vw","correlationId":"4b8e2d6a-0c9f-4a1e-b7d3-6e5a9c2f8b14"},"timestamp":"2026-07-01T22:51:41.447Z"}}}},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/auth/logout":{"post":{"operationId":"logoutUser","summary":"Logout user","description":"Revokes the current refresh token (if present) and clears the refreshToken cookie. Succeeds even without a token — the endpoint requires no authentication and always returns 200 for a well-formed request.","tags":["Authentication"],"security":[],"x-consequential":false,"responses":{"200":{"description":"Logged out successfully (refreshToken cookie cleared)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Logged out successfully"}}}}}},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/auth/verify":{"get":{"operationId":"verifyToken","summary":"Verify token validity","description":"Checks if the JWT access token is valid. Returns the same full profile payload as GET /auth/profile (both are served by the same handler).","tags":["Authentication"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Token is valid — body matches GET /auth/profile","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"user":{"type":"object","description":"Full user profile — see GET /auth/profile for the complete field list","properties":{"id":{"type":"string","format":"uuid","example":"b7e9d2c4-5f1a-4e8b-9c3d-2a6f8e0b4d17"},"email":{"type":"string","format":"email","example":"sarah.chen@gmail.com"},"role":{"type":"array","items":{"type":"string"},"example":["agent"]}}}}}}}}}},"401":{"description":"Token missing, invalid, or expired"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/auth/profile":{"get":{"operationId":"getUserProfile","summary":"Get user profile","description":"Returns authenticated user's profile information","tags":["Authentication"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Profile retrieved successfully (payload is nested under data.user)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"b7e9d2c4-5f1a-4e8b-9c3d-2a6f8e0b4d17"},"email":{"type":"string","format":"email","example":"sarah.chen@gmail.com"},"username":{"type":"string","example":"sarahchen"},"firstName":{"type":"string","example":"Sarah"},"lastName":{"type":"string","example":"Chen"},"role":{"type":"array","items":{"type":"string"},"example":["agent"]},"isActive":{"type":"boolean","example":true},"status":{"type":"string","example":"active"},"emailVerified":{"type":"boolean","example":true},"licenseVerified":{"type":"boolean","example":false},"lastLogin":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"timezone":{"type":"string","example":"America/Los_Angeles"},"teamId":{"type":"string","format":"uuid","nullable":true},"teamName":{"type":"string","nullable":true},"brokerageId":{"type":"string","format":"uuid","nullable":true},"aiPlanTier":{"type":"string","example":"free"},"subscriptionTier":{"type":"string","example":"free"},"subscriptionStatus":{"type":"string","example":"none"},"hasStripeCustomer":{"type":"boolean","example":false},"scopeLevel":{"type":"string","example":"personal"},"managedTeams":{"type":"array","description":"Teams the user manages (broker/team_lead/system_admin only; [] otherwise)","items":{"type":"object"}}}}}}}}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"put":{"operationId":"updateUserProfile","summary":"Update user profile","description":"Updates authenticated user's profile information","tags":["Authentication"],"security":[{"bearerAuth":[]}],"x-consequential":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"firstName":{"type":"string","example":"Sarah"},"lastName":{"type":"string","example":"Chen"},"currentPassword":{"type":"string","format":"password","description":"Required when changing the password"},"newPassword":{"type":"string","format":"password","description":"New password — changing it revokes ALL refresh tokens (every session is logged out)"},"homeCity":{"type":"string","example":"Bakersfield"},"homeState":{"type":"string","example":"CA"},"homeZip":{"type":"string","example":"93309"},"homeLat":{"type":"number","example":35.3433},"homeLng":{"type":"number","example":-119.0587},"licensedStates":{"type":"array","items":{"type":"string"},"example":["CA"]},"searchRadiusMiles":{"type":"integer","example":25},"timezone":{"type":"string","example":"America/Los_Angeles"}}}}}},"responses":{"200":{"description":"Profile updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"b7e9d2c4-5f1a-4e8b-9c3d-2a6f8e0b4d17"},"email":{"type":"string","format":"email","example":"sarah.chen@gmail.com"},"firstName":{"type":"string","example":"Sarah"},"lastName":{"type":"string","example":"Chen"},"role":{"type":"array","items":{"type":"string"},"example":["agent"]},"isActive":{"type":"boolean","example":true},"home_city":{"type":"string","nullable":true,"example":"Bakersfield"},"home_state":{"type":"string","nullable":true,"example":"CA"},"home_zip":{"type":"string","nullable":true,"example":"93309"},"home_lat":{"type":"number","nullable":true,"example":35.3433},"home_lng":{"type":"number","nullable":true,"example":-119.0587},"licensed_states":{"type":"array","nullable":true,"items":{"type":"string"},"example":["CA"]},"search_radius_miles":{"type":"integer","nullable":true,"example":25}}},"message":{"type":"string","example":"Profile updated successfully"}}}}}},"400":{"description":"Validation error (no fields to update, missing currentPassword, or incorrect current password)"},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/auth/logout-all":{"post":{"operationId":"logoutAllDevices","summary":"Logout from all devices","description":"Invalidates all refresh tokens for the authenticated user, logging them out from all sessions","tags":["Authentication"],"security":[{"bearerAuth":[]}],"x-consequential":true,"responses":{"200":{"description":"Logged out from all devices successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Logged out from all devices successfully"}}}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/auth/sessions":{"get":{"operationId":"listActiveSessions","summary":"List active sessions","description":"Returns list of active refresh tokens/sessions for authenticated user","tags":["Authentication"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Sessions retrieved successfully (array is nested under data.sessions)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"sessions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"3f8c1d7a-9e2b-4c6f-a1d8-7b4e2c9f5a30"},"createdAt":{"type":"string","format":"date-time","example":"2026-06-28T17:03:22.481Z"},"expiresAt":{"type":"string","format":"date-time","example":"2026-07-28T17:03:22.481Z"},"ipAddress":{"type":"string","example":"203.0.113.42"},"userAgent":{"type":"string","example":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"},"deviceInfo":{"type":"object","nullable":true},"isCurrent":{"type":"boolean","description":"True for the session that made this request","example":true}}}}}}}}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api-keys":{"get":{"operationId":"listApiKeys","summary":"List API keys","description":"Returns list of API keys for authenticated user (keys are masked)","tags":["API Keys"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"API keys retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"key_preview":{"type":"string","description":"Last 8 characters of key"},"is_active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"last_used_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"}}}}}}}}},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createApiKey","summary":"Create new API key","description":"Generates a new API key for authenticated user. Key is only shown once.\n\n⚠️ **CONSEQUENTIAL ACTION**: Creates new authentication credentials.\nStore the key securely - it cannot be retrieved again.\n","tags":["API Keys"],"security":[{"bearerAuth":[]}],"x-consequential":true,"x-ai-examples":[{"query":"Create a new API key for AI integration","parameters":{"name":"Claude AI Integration","expiresInDays":365}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Descriptive name for the API key"},"expiresInDays":{"type":"integer","description":"Number of days until expiration (1-365). If omitted, the key does not expire."},"scopes":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","enum":["read","write","delete"]}},"description":"Map of resource → allowed actions (an OBJECT, not a string array), e.g.\n{\"escrows\": [\"read\", \"write\"], \"clients\": [\"read\"]}. Use resource \"all\"\nas a wildcard (e.g. {\"all\": [\"read\"]}).\n\nValid resources: all, escrows, clients, contacts, leads, appointments,\nlistings, documents, open-houses, showings, details, tasks, notes,\ncommunications, emails, integrations, settings, analytics, activity,\nnotifications, users, search, teams, vendor-applications.\n\n**If omitted, the key is created with {} (no scopes) and is DENIED (403)\non every scoped resource** — pass scopes here or grant them later via\nPATCH /api-keys/{id}/scopes.\n","example":{"all":["read"],"escrows":["read","write"]}}}}}}},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"key":{"type":"string","description":"Full API key (only shown once)"},"name":{"type":"string"},"key_prefix":{"type":"string","description":"Masked identifier (first 8 + last 4 chars)"},"scopes":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","enum":["read","write","delete"]}},"description":"Scopes stored on the key ({} when none were provided)"},"expires_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"message":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api-keys/{id}/scopes":{"patch":{"operationId":"updateApiKeyScopes","summary":"Update API key scopes","description":"Replaces the scopes object on an existing API key. Requires JWT authentication (API keys cannot manage API keys). Scopes are a map of resource → allowed actions; see POST /api-keys for the valid resource list.","tags":["API Keys"],"security":[{"bearerAuth":[]}],"x-consequential":true,"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scopes"],"properties":{"scopes":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","enum":["read","write","delete"]}},"description":"Full replacement scopes map (resource → actions)","example":{"escrows":["read","write"],"all":["read"]}}}}}}},"responses":{"200":{"description":"Scopes updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"scopes":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","enum":["read","write","delete"]}}}}},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"id":"7d3f9b2e-5a8c-4e1d-b6f0-9c2a4e8d1b57","scopes":{"escrows":["read","write"],"all":["read"]}},"timestamp":"2026-07-01T22:48:31.554Z"}}}},"400":{"description":"Validation error (scopes must be an object)"},"401":{"description":"Unauthorized"},"404":{"description":"API key not found"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api-keys/{id}/revoke":{"put":{"operationId":"revokeApiKey","summary":"Revoke API key","description":"Deactivates an API key without deleting it","tags":["API Keys"],"security":[{"bearerAuth":[]}],"x-consequential":true,"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"API key revoked successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"7d3f9b2e-5a8c-4e1d-b6f0-9c2a4e8d1b57"}}},"timestamp":{"type":"string","format":"date-time","example":"2026-07-01T22:53:07.114Z"}}}}}},"401":{"description":"Unauthorized"},"404":{"description":"API key not found"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/api-keys/{id}":{"delete":{"operationId":"deleteApiKey","summary":"Delete API key","description":"Permanently deletes an API key","tags":["API Keys"],"security":[{"bearerAuth":[]}],"x-consequential":true,"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"API key deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"description":"Unauthorized"},"404":{"description":"API key not found"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/listings":{"get":{"operationId":"listListings","summary":"List all property listings","description":"Returns paginated list of property listings with optional filtering. Default page size 25 (max 100).","tags":["Listings"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["active","pending","sold","withdrawn","expired"]}},{"name":"minPrice","in":"query","schema":{"type":"number"}},{"name":"maxPrice","in":"query","schema":{"type":"number"}},{"$ref":"#/components/parameters/pageParam"},{"$ref":"#/components/parameters/limitParam"}],"responses":{"200":{"description":"Paginated list — records under data.listings, pagination under data.meta (the envelope also carries data.stats aggregates)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"listings":{"type":"array","items":{"$ref":"#/components/schemas/Listing"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"listings":[{"id":"550e8400-e29b-41d4-a716-446655440000","mls_number":"ML81992437","address":"456 Oak Ave, Tehachapi, CA 93561","city":"Tehachapi","state":"CA","zip_code":"93561","list_price":425000,"status":"active","property_type":"single_family","bedrooms":4,"bathrooms":3,"square_feet":2800}],"meta":{"page":1,"limit":25,"total":87,"totalPages":4,"hasMore":true}},"timestamp":"2026-07-01T22:45:03.120Z"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createListing","summary":"Create new listing","tags":["Listings"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["address","list_price"],"properties":{"address":{"type":"string","description":"Street address of the property"},"list_price":{"type":"number","description":"Listing price in USD"},"property_type":{"type":"string","description":"Property type (e.g. single_family, condo, townhouse, multi_family, land, commercial)"},"bedrooms":{"type":"integer","description":"Number of bedrooms"},"bathrooms":{"type":"number","description":"Number of bathrooms"}}}}}},"responses":{"201":{"description":"Listing created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Listing"},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"id":"8c5e2a9f-4d7b-4e3a-b1c8-6f0d9e2a5c74","address":"1847 Cerro Vista Dr, Bakersfield, CA 93306","list_price":389000,"status":"active","property_type":"single_family","bedrooms":3,"bathrooms":2,"version":1,"created_at":"2026-07-01T22:46:18.402Z","updated_at":"2026-07-01T22:46:18.402Z"},"timestamp":"2026-07-01T22:46:18.410Z"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/listings/{id}":{"get":{"operationId":"getListingById","summary":"Get listing by ID","tags":["Listings"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Listing found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Listing"},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"id":"550e8400-e29b-41d4-a716-446655440000","mls_number":"ML81992437","address":"456 Oak Ave, Tehachapi, CA 93561","city":"Tehachapi","state":"CA","zip_code":"93561","list_price":425000,"status":"active","property_type":"single_family","bedrooms":4,"bathrooms":3,"square_feet":2800,"year_built":2010,"version":3},"timestamp":"2026-07-01T22:47:00.115Z"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"put":{"operationId":"updateListing","summary":"Update listing","tags":["Listings"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"parameters":[{"$ref":"#/components/parameters/idParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"list_price":{"type":"number","description":"Listing price in USD"},"status":{"type":"string","description":"Listing status (active, pending, sold, withdrawn, expired)"},"version":{"type":"integer","description":"Current record version for optimistic locking"}}}}}},"responses":{"200":{"description":"Listing updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Listing"},"timestamp":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteListing","summary":"Delete listing","description":"Permanently deletes a listing (hard delete — only allowed after the listing has been archived)","tags":["Listings"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Listing deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients":{"get":{"operationId":"listClients","summary":"List all clients","description":"Returns paginated list of client contacts. Default page size 25 (max 100).","tags":["Clients"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"client_type","in":"query","schema":{"type":"string","enum":["buyer","seller","both"]}},{"name":"status","in":"query","schema":{"type":"string","enum":["active","inactive","closed"]}},{"$ref":"#/components/parameters/pageParam"},{"$ref":"#/components/parameters/limitParam"}],"responses":{"200":{"description":"Paginated list — records under data.clients, pagination under data.meta","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"clients":{"type":"array","items":{"$ref":"#/components/schemas/Client"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}},"example":{"success":true,"data":{"clients":[{"id":"a3f8c1d2-6b4e-4a9f-8d27-95c0e3b1f684","first_name":"Michael","last_name":"Torres","email":"michael.torres@gmail.com","phone":"(661) 555-0142","client_type":"buyer","status":"active","source":"Zillow","budget_min":350000,"budget_max":475000}],"meta":{"page":1,"limit":25,"total":42,"totalPages":2,"hasMore":true}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createClient","summary":"Create new client","tags":["Clients"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["first_name","last_name","client_type"],"properties":{"first_name":{"type":"string","description":"Client's first name"},"last_name":{"type":"string","description":"Client's last name"},"email":{"type":"string","description":"Client's email address"},"phone":{"type":"string","description":"Client's phone number"},"client_type":{"type":"string","enum":["buyer","seller","both"],"description":"Whether the client is a buyer, seller, or both"}}}}}},"responses":{"201":{"description":"Client created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Client"}}},"example":{"success":true,"data":{"id":"a3f8c1d2-6b4e-4a9f-8d27-95c0e3b1f684","first_name":"Michael","last_name":"Torres","email":"michael.torres@gmail.com","phone":"(661) 555-0142","client_type":"buyer","status":"active","version":1,"created_at":"2026-07-01T22:49:27.331Z","updated_at":"2026-07-01T22:49:27.331Z"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/clients/{id}":{"get":{"operationId":"getClientById","summary":"Get client by ID","tags":["Clients"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Client found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Client"}}},"example":{"success":true,"data":{"id":"a3f8c1d2-6b4e-4a9f-8d27-95c0e3b1f684","first_name":"Michael","last_name":"Torres","email":"michael.torres@gmail.com","phone":"(661) 555-0142","client_type":"buyer","status":"active","source":"Zillow","budget_min":350000,"budget_max":475000,"pre_approved":true,"pre_approval_amount":460000,"version":2}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"put":{"operationId":"updateClient","summary":"Update client","tags":["Clients"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"parameters":[{"$ref":"#/components/parameters/idParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"Client's email address"},"phone":{"type":"string","description":"Client's phone number"},"status":{"type":"string","description":"Client status (active, inactive, closed)"},"version":{"type":"integer","description":"Current record version for optimistic locking"}}}}}},"responses":{"200":{"description":"Client updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Client"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteClient","summary":"Delete client","tags":["Clients"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Client deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/appointments":{"get":{"operationId":"listAppointments","summary":"List all appointments","description":"Returns paginated list of appointments/showings. Default page size 25 (max 100).","tags":["Appointments"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"appointment_type","in":"query","schema":{"type":"string","enum":["showing","inspection","signing","meeting","call","other"]}},{"name":"status","in":"query","schema":{"type":"string","enum":["scheduled","completed","cancelled","no_show"]}},{"name":"start_date","in":"query","schema":{"type":"string","format":"date"}},{"$ref":"#/components/parameters/pageParam"},{"$ref":"#/components/parameters/limitParam"}],"responses":{"200":{"description":"Paginated list — records under data.appointments, pagination under data.meta","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"appointments":{"type":"array","items":{"$ref":"#/components/schemas/Appointment"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"appointments":[{"id":"d4b7a9e2-8c1f-4d6a-b3e5-7f9c2a0d8b46","title":"Buyer consultation — Torres family","appointment_type":"meeting","start_time":"2026-07-10T17:00:00Z","end_time":"2026-07-10T18:00:00Z","location":"9900 Stockdale Hwy, Bakersfield, CA 93311","client_id":"a3f8c1d2-6b4e-4a9f-8d27-95c0e3b1f684","status":"scheduled"}],"meta":{"page":1,"limit":25,"total":12,"totalPages":1,"hasMore":false}},"timestamp":"2026-07-01T22:50:41.207Z"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createAppointment","summary":"Create new appointment","tags":["Appointments"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","start_time","end_time"],"properties":{"title":{"type":"string","description":"Appointment title"},"start_time":{"type":"string","format":"date-time","description":"Appointment start time (ISO 8601)"},"end_time":{"type":"string","format":"date-time","description":"Appointment end time (ISO 8601)"},"appointment_type":{"type":"string","description":"Type of appointment (showing, inspection, signing, meeting, call, other)"},"location":{"type":"string","description":"Appointment location"}}}}}},"responses":{"201":{"description":"Appointment created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Appointment"},"message":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"id":"d4b7a9e2-8c1f-4d6a-b3e5-7f9c2a0d8b46","title":"Showing — 456 Oak Ave","appointment_type":"showing","start_time":"2026-07-12T21:30:00Z","end_time":"2026-07-12T22:00:00Z","location":"456 Oak Ave, Tehachapi, CA 93561","status":"scheduled","version":1},"message":"Appointment created successfully","timestamp":"2026-07-01T22:51:12.940Z"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/appointments/{id}":{"get":{"operationId":"getAppointmentById","summary":"Get appointment by ID","tags":["Appointments"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Appointment found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Appointment"},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"id":"d4b7a9e2-8c1f-4d6a-b3e5-7f9c2a0d8b46","title":"Buyer consultation — Torres family","appointment_type":"meeting","start_time":"2026-07-10T17:00:00Z","end_time":"2026-07-10T18:00:00Z","location":"9900 Stockdale Hwy, Bakersfield, CA 93311","client_id":"a3f8c1d2-6b4e-4a9f-8d27-95c0e3b1f684","status":"scheduled","version":1},"timestamp":"2026-07-01T22:51:44.518Z"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"put":{"operationId":"updateAppointment","summary":"Update appointment","tags":["Appointments"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"parameters":[{"$ref":"#/components/parameters/idParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"start_time":{"type":"string","format":"date-time","description":"Appointment start time (ISO 8601)"},"end_time":{"type":"string","format":"date-time","description":"Appointment end time (ISO 8601)"},"status":{"type":"string","description":"Appointment status (scheduled, completed, cancelled, no_show)"},"version":{"type":"integer","description":"Current record version for optimistic locking"}}}}}},"responses":{"200":{"description":"Appointment updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Appointment"},"timestamp":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteAppointment","summary":"Delete appointment","tags":["Appointments"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Appointment deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/leads":{"get":{"operationId":"listLeads","summary":"List all leads","description":"Returns paginated list of prospective client leads. Default page size 25 (max 100).","tags":["Leads"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["new","contacted","qualified","unqualified","converted","lost"]}},{"name":"interest_level","in":"query","schema":{"type":"string","enum":["hot","warm","cold"]}},{"$ref":"#/components/parameters/pageParam"},{"$ref":"#/components/parameters/limitParam"}],"responses":{"200":{"description":"Paginated list — records under data.leads, pagination under data.meta (the envelope also carries data.stats and data.cursors)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"leads":{"type":"array","items":{"$ref":"#/components/schemas/Lead"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"leads":[{"id":"f2b8d4a6-3c5e-4f7a-9b1d-8e0c6a4f2d9b","name":"Rachel Kim","email":"rachel.kim@outlook.com","phone":"(661) 555-0198","source":"Website Form","status":"new","lead_type":"buyer","interest_level":"warm","budget":380000,"timeline":"3-6 months"}],"meta":{"page":1,"limit":25,"total":34,"totalPages":2,"hasMore":true}},"timestamp":"2026-07-01T22:52:30.664Z"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createLead","summary":"Create new lead","tags":["Leads"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Lead's full name"},"email":{"type":"string","description":"Lead's email address"},"phone":{"type":"string","description":"Lead's phone number"},"source":{"type":"string","description":"How the lead was acquired (e.g. Website Form, Zillow)"},"lead_type":{"type":"string","enum":["buyer","seller","both"],"description":"Whether the lead is a buyer, seller, or both"}}}}}},"responses":{"201":{"description":"Lead created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Lead"},"message":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"id":"f2b8d4a6-3c5e-4f7a-9b1d-8e0c6a4f2d9b","name":"Rachel Kim","email":"rachel.kim@outlook.com","phone":"(661) 555-0198","source":"Website Form","status":"new","lead_type":"buyer","interest_level":"warm","version":1,"created_at":"2026-07-01T22:53:05.882Z"},"message":"Lead created successfully","timestamp":"2026-07-01T22:53:05.890Z"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/leads/{id}":{"get":{"operationId":"getLeadById","summary":"Get lead by ID","tags":["Leads"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Lead found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Lead"},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"id":"f2b8d4a6-3c5e-4f7a-9b1d-8e0c6a4f2d9b","name":"Rachel Kim","email":"rachel.kim@outlook.com","phone":"(661) 555-0198","source":"Website Form","status":"contacted","lead_type":"buyer","interest_level":"warm","budget":380000,"timeline":"3-6 months","version":2},"timestamp":"2026-07-01T22:53:41.126Z"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"put":{"operationId":"updateLead","summary":"Update lead","tags":["Leads"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"parameters":[{"$ref":"#/components/parameters/idParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","description":"Lead status (new, contacted, qualified, unqualified, converted, lost)"},"interest_level":{"type":"string","description":"Lead's level of interest (hot, warm, cold)"},"version":{"type":"integer","description":"Current record version for optimistic locking"}}}}}},"responses":{"200":{"description":"Lead updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Lead"},"timestamp":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteLead","summary":"Delete lead","tags":["Leads"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"parameters":[{"$ref":"#/components/parameters/idParam"}],"responses":{"200":{"description":"Lead deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/leads/{id}/convert":{"post":{"operationId":"convertLeadToClient","summary":"Convert lead to client","description":"Converts a qualified lead into a full client record (transactional). Creates or reuses a contact, creates the client, and marks the lead converted.","tags":["Leads"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"x-consequential":true,"parameters":[{"$ref":"#/components/parameters/idParam"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"clientType":{"type":"string","enum":["buyer","seller","both"],"default":"buyer","description":"Client type for the new client record"}}}}}},"responses":{"200":{"description":"Lead converted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"client":{"type":"object","description":"Newly created client record"},"lead":{"type":"object","description":"Updated lead record (lead_status set to converted, client_id linked)"},"primaryContactId":{"type":"string","format":"uuid","description":"Contact used (or created) as the client's primary contact"},"additionalContactsCount":{"type":"integer","description":"Number of additional lead contacts not carried onto the client"}}},"message":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"example":{"success":true,"data":{"client":{"id":"c9d2e4f6-1a3b-4c5d-8e7f-0b2d4f6a8c1e","contact_id":"7e5a3c1b-9d8f-4e2a-b6c4-1f0e8d7a5b3c","client_type":"buyer","status":"active","price_range_min":342000,"price_range_max":418000},"lead":{"id":"f2b8d4a6-3c5e-4f7a-9b1d-8e0c6a4f2d9b","lead_status":"converted","client_id":"c9d2e4f6-1a3b-4c5d-8e7f-0b2d4f6a8c1e"},"primaryContactId":"7e5a3c1b-9d8f-4e2a-b6c4-1f0e8d7a5b3c","additionalContactsCount":0},"message":"Lead successfully converted to client","timestamp":"2026-07-01T22:54:29.773Z"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/webhooks":{"get":{"operationId":"listWebhooks","summary":"List webhook subscriptions","description":"Returns the webhook subscriptions registered for your account. Requires the broker or system admin role.","tags":["Webhooks"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"$ref":"#/components/parameters/pageParam"},{"$ref":"#/components/parameters/limitParam"}],"responses":{"200":{"description":"Webhook subscriptions","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Requires broker or system admin role"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"post":{"operationId":"createWebhook","summary":"Create a webhook subscription","description":"Registers an endpoint to receive event notifications. Each delivery is an HTTPS POST with the JSON payload, an `X-Webhook-Event` header naming the event, an `X-Webhook-Timestamp` header, and an `X-Webhook-Signature` header containing `sha256=` followed by the hex-encoded HMAC-SHA256 of the payload computed with your secret. Each event gets 4 delivery attempts total: the initial delivery plus retries after 1, 5, and 15 minutes. Only HTTP 5xx, 408, and 429 responses (and network failures) are retried — any other 4xx response is logged and NOT retried.\n","tags":["Webhooks"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events","secret"],"properties":{"url":{"type":"string","format":"uri","description":"Endpoint to deliver events to"},"events":{"type":"array","description":"Event names to subscribe to (see GET /webhooks/events for the catalog)","items":{"type":"string","example":"escrow.created"}},"secret":{"type":"string","minLength":10,"description":"Shared secret used to sign every delivery"}}}}}},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Webhook"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Requires broker or system admin role"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/webhooks/events":{"get":{"operationId":"listWebhookEvents","summary":"List available webhook events","description":"Returns the catalog of events you can subscribe to, including each event's category, description, and the field names included in its payload.","tags":["Webhooks"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"category","in":"query","description":"Filter to a single category (e.g. escrow, lead, email)","schema":{"type":"string"}}],"responses":{"200":{"description":"Event catalog","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"event":{"type":"string","example":"escrow.created"},"category":{"type":"string","example":"escrow"},"description":{"type":"string"},"payload":{"type":"array","description":"Field names included in the event's data object","items":{"type":"string"}}}}},"meta":{"type":"object","description":"Catalog totals. When filtered with `?category=`, meta instead contains `category` and `count`.","properties":{"total":{"type":"integer","description":"Number of events in the catalog"},"categories":{"type":"array","description":"All category names, sorted alphabetically","items":{"type":"string","example":"escrow"}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Requires broker or system admin role"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/webhooks/events/categories":{"get":{"operationId":"listWebhookEventCategories","summary":"List webhook event categories","description":"Returns every event category with the number of events it contains.","tags":["Webhooks"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"responses":{"200":{"description":"Categories with event counts","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string","example":"escrow"},"event_count":{"type":"integer"}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"403":{"description":"Requires broker or system admin role"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/webhooks/{id}":{"put":{"operationId":"updateWebhook","summary":"Update a webhook subscription","description":"Updates a subscription's URL, events, secret, or active flag. Only the fields you send are changed.","tags":["Webhooks"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Webhook ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"Endpoint that receives event deliveries"},"events":{"type":"array","description":"Subscribed event names (entity.action format)","items":{"type":"string"}},"active":{"type":"boolean","description":"Whether the subscription is enabled to receive deliveries"},"secret":{"type":"string","minLength":10,"description":"Shared secret used to sign deliveries (minimum 10 characters)"}}}}}},"responses":{"200":{"description":"Webhook updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Webhook"}}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}},"delete":{"operationId":"deleteWebhook","summary":"Deactivate a webhook subscription","description":"Deactivates a subscription so it stops receiving deliveries. The subscription record is kept and can be re-enabled by setting `active` back to true.","tags":["Webhooks"],"x-consequential":true,"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Webhook ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook deactivated (response is the updated subscription with active=false)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Webhook"},"timestamp":{"type":"string","format":"date-time","example":"2026-07-01T22:51:14.902Z"}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}},"/webhooks/{id}/logs":{"get":{"operationId":"getWebhookLogs","summary":"Get webhook delivery logs","description":"Returns recent delivery attempts for a subscription, including the payload sent, the HTTP status your endpoint returned, and whether delivery succeeded.","tags":["Webhooks"],"security":[{"bearerAuth":[]},{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Webhook ID","schema":{"type":"string"}},{"$ref":"#/components/parameters/pageParam"},{"$ref":"#/components/parameters/limitParam"}],"responses":{"200":{"description":"Delivery log entries, most recent first","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"webhook_id":{"type":"string"},"event":{"type":"string","example":"escrow.created"},"payload":{"type":"object","description":"The delivered JSON body"},"response_status":{"type":"integer","description":"HTTP status your endpoint returned (0 if the connection failed)"},"delivered_at":{"type":"string","format":"date-time","nullable":true,"description":"Set when delivery succeeded; null for failed attempts"},"created_at":{"type":"string","format":"date-time"}}}}}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"$ref":"#/components/responses/NotFoundError"},"429":{"$ref":"#/components/responses/RateLimitError"},"500":{"$ref":"#/components/responses/ServerError"}}}}}}