{
  "openapi": "3.1.0",
  "info": {
    "title": "URBLD API",
    "version": "0.1.0",
    "summary": "Operating system and AI-agent infrastructure for service businesses.",
    "description": "The URBLD API exposes the full lead-to-payment lifecycle (CRM, scheduling, contracts, jobs, invoicing, payments, follow-ups, communications) as governed capabilities that both humans and AI agents can consume. All operations are strictly tenant-scoped; every destructive mutation is written to the tenant audit log.\n\nCompanion documents:\n- Machine-readable capability manifest: https://urbld.com/.well-known/ai-capabilities.json\n- LLM crawler guide: https://urbld.com/llms.txt\n- Sitemap: https://urbld.com/sitemap.xml",
    "termsOfService": "https://urbld.com/legal/terms",
    "contact": {
      "name": "URBLD",
      "url": "https://urbld.com/contact"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://urbld.com/legal/terms"
    }
  },
  "servers": [
    {
      "url": "https://api.urbld.com/v1",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "URBLD product documentation",
    "url": "https://urbld.com/docs"
  },
  "tags": [
    { "name": "Leads", "description": "Inbound leads, deduplication, qualification." },
    { "name": "Customers", "description": "Long-lived customer records with lifecycle_number continuity." },
    { "name": "Scheduling", "description": "Availability, appointment booking, dispatch." },
    { "name": "Estimates", "description": "Line-item estimates from scope, calculator, or measurement." },
    { "name": "Contracts", "description": "E-signature contract packages." },
    { "name": "Jobs", "description": "Sold jobs from contract through completion and warranty." },
    { "name": "Invoices", "description": "Invoice issuance and status." },
    { "name": "Payments", "description": "Payment capture and reconciliation." },
    { "name": "Follow-Ups", "description": "SMS/email/call follow-up scheduling and recovery." },
    { "name": "Communications", "description": "Unified inbox threading across SMS and email." },
    { "name": "Jarvis", "description": "Grounded AI manager queries." }
  ],
  "security": [
    { "oauth2": ["leads.read"] }
  ],
  "paths": {
    "/leads": {
      "get": {
        "tags": ["Leads"],
        "summary": "List leads",
        "operationId": "listLeads",
        "security": [{ "oauth2": ["leads.read"] }],
        "parameters": [
          { "$ref": "#/components/parameters/Cursor" },
          { "$ref": "#/components/parameters/Limit" },
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["new", "qualifying", "qualified", "disqualified", "converted"] } }
        ],
        "responses": {
          "200": { "$ref": "#/components/responses/LeadList" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "tags": ["Leads"],
        "summary": "Capture a lead",
        "description": "Create a new lead. Deduplicated within the tenant by normalized phone and email.",
        "operationId": "captureLead",
        "security": [{ "oauth2": ["leads.write"] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/LeadInput" }
            }
          }
        },
        "responses": {
          "201": { "$ref": "#/components/responses/Lead" },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "409": { "$ref": "#/components/responses/Conflict" }
        }
      }
    },
    "/leads/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/Id" }],
      "get": {
        "tags": ["Leads"],
        "summary": "Get a lead",
        "operationId": "getLead",
        "security": [{ "oauth2": ["leads.read"] }],
        "responses": {
          "200": { "$ref": "#/components/responses/Lead" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "tags": ["Leads"],
        "summary": "Update a lead",
        "operationId": "updateLead",
        "security": [{ "oauth2": ["leads.write"] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/LeadInput" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Lead" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/leads/{id}/qualify": {
      "parameters": [{ "$ref": "#/components/parameters/Id" }],
      "post": {
        "tags": ["Leads"],
        "summary": "Qualify a lead",
        "operationId": "qualifyLead",
        "security": [{ "oauth2": ["leads.write"] }],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "outcome": { "type": "string", "enum": ["qualified", "disqualified", "callback"] },
                  "notes": { "type": "string" }
                },
                "required": ["outcome"]
              }
            }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Lead" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/customers": {
      "get": {
        "tags": ["Customers"],
        "summary": "List customers",
        "operationId": "listCustomers",
        "security": [{ "oauth2": ["customers.read"] }],
        "parameters": [{ "$ref": "#/components/parameters/Cursor" }, { "$ref": "#/components/parameters/Limit" }],
        "responses": { "200": { "$ref": "#/components/responses/CustomerList" } }
      },
      "put": {
        "tags": ["Customers"],
        "summary": "Upsert customer",
        "operationId": "upsertCustomer",
        "security": [{ "oauth2": ["customers.write"] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CustomerInput" } } }
        },
        "responses": { "200": { "$ref": "#/components/responses/Customer" }, "400": { "$ref": "#/components/responses/BadRequest" } }
      }
    },
    "/scheduling/availability": {
      "get": {
        "tags": ["Scheduling"],
        "summary": "Get availability",
        "operationId": "getAvailability",
        "security": [{ "oauth2": ["scheduling.read"] }],
        "parameters": [
          { "name": "service", "in": "query", "required": true, "schema": { "type": "string" } },
          { "name": "from", "in": "query", "required": true, "schema": { "type": "string", "format": "date-time" } },
          { "name": "to", "in": "query", "required": true, "schema": { "type": "string", "format": "date-time" } },
          { "name": "territory", "in": "query", "schema": { "type": "string" } },
          { "name": "skills", "in": "query", "style": "form", "explode": false, "schema": { "type": "array", "items": { "type": "string" } } }
        ],
        "responses": {
          "200": {
            "description": "Open appointment slots.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "slots": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "start": { "type": "string", "format": "date-time" },
                          "end": { "type": "string", "format": "date-time" },
                          "technician_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/scheduling/appointments": {
      "post": {
        "tags": ["Scheduling"],
        "summary": "Book an appointment",
        "operationId": "bookAppointment",
        "security": [{ "oauth2": ["scheduling.write"] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AppointmentInput" } } }
        },
        "responses": { "201": { "$ref": "#/components/responses/Appointment" }, "409": { "$ref": "#/components/responses/Conflict" } }
      }
    },
    "/estimates": {
      "post": {
        "tags": ["Estimates"],
        "summary": "Create estimate",
        "operationId": "createEstimate",
        "security": [{ "oauth2": ["estimates.write"] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EstimateInput" } } }
        },
        "responses": { "201": { "$ref": "#/components/responses/Estimate" } }
      }
    },
    "/contracts/{id}/send": {
      "parameters": [{ "$ref": "#/components/parameters/Id" }],
      "post": {
        "tags": ["Contracts"],
        "summary": "Send a contract for signature",
        "operationId": "sendContract",
        "security": [{ "oauth2": ["contracts.write"] }],
        "responses": { "202": { "description": "Contract queued for delivery." }, "404": { "$ref": "#/components/responses/NotFound" } }
      }
    },
    "/jobs": {
      "post": {
        "tags": ["Jobs"],
        "summary": "Create a job",
        "description": "Convert a signed contract into an operational job.",
        "operationId": "createJob",
        "security": [{ "oauth2": ["jobs.write"] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JobInput" } } }
        },
        "responses": { "201": { "$ref": "#/components/responses/Job" } }
      }
    },
    "/invoices": {
      "post": {
        "tags": ["Invoices"],
        "summary": "Issue invoice",
        "operationId": "issueInvoice",
        "security": [{ "oauth2": ["invoices.write"] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InvoiceInput" } } }
        },
        "responses": { "201": { "$ref": "#/components/responses/Invoice" } }
      }
    },
    "/payments": {
      "post": {
        "tags": ["Payments"],
        "summary": "Record a payment",
        "operationId": "recordPayment",
        "security": [{ "oauth2": ["payments.read"] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaymentInput" } } }
        },
        "responses": { "201": { "$ref": "#/components/responses/Payment" } }
      }
    },
    "/follow-ups": {
      "post": {
        "tags": ["Follow-Ups"],
        "summary": "Schedule a follow-up",
        "operationId": "scheduleFollowUp",
        "security": [{ "oauth2": ["communications.write"] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FollowUpInput" } } }
        },
        "responses": { "201": { "description": "Follow-up created." } }
      }
    },
    "/communications": {
      "get": {
        "tags": ["Communications"],
        "summary": "List communications for an entity",
        "operationId": "listCommunications",
        "security": [{ "oauth2": ["communications.read"] }],
        "parameters": [
          { "name": "entity_type", "in": "query", "required": true, "schema": { "type": "string", "enum": ["lead", "customer", "job"] } },
          { "name": "entity_id", "in": "query", "required": true, "schema": { "type": "string", "format": "uuid" } },
          { "$ref": "#/components/parameters/Cursor" },
          { "$ref": "#/components/parameters/Limit" }
        ],
        "responses": { "200": { "description": "Threaded communication list." } }
      },
      "post": {
        "tags": ["Communications"],
        "summary": "Send a communication",
        "operationId": "sendCommunication",
        "security": [{ "oauth2": ["communications.write"] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommunicationInput" } } }
        },
        "responses": { "202": { "description": "Message queued for delivery." } }
      }
    },
    "/jarvis/ask": {
      "post": {
        "tags": ["Jarvis"],
        "summary": "Ask Jarvis",
        "description": "Query the Jarvis manager agent. All numeric answers are grounded on tool calls against the tenant's own data — never hallucinated.",
        "operationId": "askJarvis",
        "security": [{ "oauth2": ["leads.read", "customers.read", "jobs.read"] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["prompt"],
                "properties": {
                  "prompt": { "type": "string" },
                  "conversation_id": { "type": "string", "format": "uuid" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Grounded response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "answer": { "type": "string" },
                    "tool_calls": { "type": "array", "items": { "type": "object" } }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.0. Use authorization_code for user-delegated access and client_credentials for machine / agent access.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://urbld.com/oauth/authorize",
            "tokenUrl": "https://urbld.com/oauth/token",
            "scopes": {
              "leads.read": "Read leads",
              "leads.write": "Create and update leads",
              "customers.read": "Read customers",
              "customers.write": "Create and update customers",
              "jobs.read": "Read jobs",
              "jobs.write": "Create and update jobs",
              "estimates.read": "Read estimates",
              "estimates.write": "Create and update estimates",
              "contracts.read": "Read contracts",
              "contracts.write": "Create and send contracts",
              "invoices.read": "Read invoices",
              "invoices.write": "Issue invoices",
              "payments.read": "Read and record payments",
              "communications.read": "Read the unified inbox",
              "communications.write": "Send communications",
              "scheduling.read": "Read availability and appointments",
              "scheduling.write": "Book and modify appointments"
            }
          },
          "clientCredentials": {
            "tokenUrl": "https://urbld.com/oauth/token",
            "scopes": {
              "leads.read": "Read leads",
              "leads.write": "Create and update leads",
              "customers.read": "Read customers",
              "customers.write": "Create and update customers",
              "jobs.read": "Read jobs",
              "jobs.write": "Create and update jobs",
              "estimates.read": "Read estimates",
              "estimates.write": "Create and update estimates",
              "contracts.read": "Read contracts",
              "contracts.write": "Create and send contracts",
              "invoices.read": "Read invoices",
              "invoices.write": "Issue invoices",
              "payments.read": "Read and record payments",
              "communications.read": "Read the unified inbox",
              "communications.write": "Send communications",
              "scheduling.read": "Read availability and appointments",
              "scheduling.write": "Book and modify appointments"
            }
          }
        }
      }
    },
    "parameters": {
      "Id": { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } },
      "Cursor": { "name": "cursor", "in": "query", "schema": { "type": "string" }, "description": "Opaque pagination cursor." },
      "Limit": { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 } }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" },
              "details": { "type": "object", "additionalProperties": true }
            }
          }
        }
      },
      "LeadInput": {
        "type": "object",
        "required": ["contact"],
        "properties": {
          "contact": {
            "type": "object",
            "properties": {
              "first_name": { "type": "string" },
              "last_name": { "type": "string" },
              "phone": { "type": "string" },
              "email": { "type": "string", "format": "email" }
            }
          },
          "source": { "type": "string", "description": "Origin channel (e.g. website, meta_ads, google_lsa)." },
          "service_type": { "type": "string" },
          "address": { "type": "string" },
          "notes": { "type": "string" },
          "tags": { "type": "array", "items": { "type": "string" } }
        }
      },
      "Lead": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "lifecycle_number": { "type": "string" },
          "status": { "type": "string" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" },
          "contact": { "type": "object" },
          "source": { "type": "string" },
          "tags": { "type": "array", "items": { "type": "string" } }
        }
      },
      "CustomerInput": {
        "type": "object",
        "properties": {
          "lead_id": { "type": "string", "format": "uuid", "description": "Preserves lifecycle_number continuity from the originating lead." },
          "first_name": { "type": "string" },
          "last_name": { "type": "string" },
          "phone": { "type": "string" },
          "email": { "type": "string", "format": "email" },
          "address": { "type": "string" }
        }
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "lifecycle_number": { "type": "string" },
          "first_name": { "type": "string" },
          "last_name": { "type": "string" },
          "phone": { "type": "string" },
          "email": { "type": "string", "format": "email" }
        }
      },
      "AppointmentInput": {
        "type": "object",
        "required": ["start", "end", "customer_id"],
        "properties": {
          "customer_id": { "type": "string", "format": "uuid" },
          "lead_id": { "type": "string", "format": "uuid" },
          "start": { "type": "string", "format": "date-time" },
          "end": { "type": "string", "format": "date-time" },
          "technician_id": { "type": "string", "format": "uuid" },
          "service": { "type": "string" },
          "notes": { "type": "string" }
        }
      },
      "Appointment": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "start": { "type": "string", "format": "date-time" },
          "end": { "type": "string", "format": "date-time" },
          "status": { "type": "string", "enum": ["booked", "confirmed", "en_route", "completed", "canceled", "no_show"] }
        }
      },
      "EstimateInput": {
        "type": "object",
        "required": ["customer_id", "line_items"],
        "properties": {
          "customer_id": { "type": "string", "format": "uuid" },
          "lead_id": { "type": "string", "format": "uuid" },
          "line_items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["description", "quantity", "unit_price"],
              "properties": {
                "description": { "type": "string" },
                "quantity": { "type": "number" },
                "unit_price": { "type": "number" },
                "sku": { "type": "string" }
              }
            }
          }
        }
      },
      "Estimate": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "status": { "type": "string", "enum": ["draft", "sent", "accepted", "declined", "expired"] },
          "total": { "type": "number" }
        }
      },
      "JobInput": {
        "type": "object",
        "required": ["contract_id"],
        "properties": {
          "contract_id": { "type": "string", "format": "uuid" },
          "scheduled_start": { "type": "string", "format": "date-time" },
          "crew_ids": { "type": "array", "items": { "type": "string", "format": "uuid" } }
        }
      },
      "Job": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "lifecycle_number": { "type": "string" },
          "status": { "type": "string" }
        }
      },
      "InvoiceInput": {
        "type": "object",
        "required": ["job_id", "amount"],
        "properties": {
          "job_id": { "type": "string", "format": "uuid" },
          "amount": { "type": "number" },
          "milestone": { "type": "string", "enum": ["deposit", "progress", "final"] }
        }
      },
      "Invoice": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "status": { "type": "string", "enum": ["draft", "sent", "partial", "paid", "void"] },
          "amount_due": { "type": "number" },
          "amount_paid": { "type": "number" }
        }
      },
      "PaymentInput": {
        "type": "object",
        "required": ["invoice_id", "amount"],
        "properties": {
          "invoice_id": { "type": "string", "format": "uuid" },
          "amount": { "type": "number" },
          "method": { "type": "string", "enum": ["card", "ach", "cash", "check", "other"] },
          "external_id": { "type": "string", "description": "Provider reference (e.g. Stripe charge id)." }
        }
      },
      "Payment": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "invoice_id": { "type": "string", "format": "uuid" },
          "amount": { "type": "number" },
          "status": { "type": "string", "enum": ["pending", "settled", "failed", "refunded"] }
        }
      },
      "FollowUpInput": {
        "type": "object",
        "required": ["entity_type", "entity_id", "channel", "scheduled_for"],
        "properties": {
          "entity_type": { "type": "string", "enum": ["lead", "estimate", "job"] },
          "entity_id": { "type": "string", "format": "uuid" },
          "channel": { "type": "string", "enum": ["sms", "email", "call"] },
          "scheduled_for": { "type": "string", "format": "date-time" },
          "template": { "type": "string" },
          "assignee_id": { "type": "string", "format": "uuid" }
        }
      },
      "CommunicationInput": {
        "type": "object",
        "required": ["entity_type", "entity_id", "channel", "body"],
        "properties": {
          "entity_type": { "type": "string", "enum": ["lead", "customer", "job"] },
          "entity_id": { "type": "string", "format": "uuid" },
          "channel": { "type": "string", "enum": ["sms", "email"] },
          "subject": { "type": "string" },
          "body": { "type": "string" }
        }
      }
    },
    "responses": {
      "Lead": { "description": "A lead.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Lead" } } } },
      "LeadList": {
        "description": "Paginated leads.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "data": { "type": "array", "items": { "$ref": "#/components/schemas/Lead" } },
                "next_cursor": { "type": "string", "nullable": true }
              }
            }
          }
        }
      },
      "Customer": { "description": "A customer.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Customer" } } } },
      "CustomerList": {
        "description": "Paginated customers.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "data": { "type": "array", "items": { "$ref": "#/components/schemas/Customer" } },
                "next_cursor": { "type": "string", "nullable": true }
              }
            }
          }
        }
      },
      "Appointment": { "description": "A booked appointment.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Appointment" } } } },
      "Estimate": { "description": "An estimate.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Estimate" } } } },
      "Job": { "description": "A job.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Job" } } } },
      "Invoice": { "description": "An invoice.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Invoice" } } } },
      "Payment": { "description": "A payment.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Payment" } } } },
      "BadRequest": { "description": "Validation error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Unauthorized": { "description": "Missing or invalid OAuth token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "NotFound": { "description": "Resource not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Conflict": { "description": "State or dedupe conflict.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    }
  }
}
