{
  "openapi": "3.1.0",
  "info": {
    "title": "aBlueC public API",
    "version": "1.0.0",
    "summary": "Find local service pros who are available now, and send one of them a request the customer confirms.",
    "description": "aBlueC (https://abluec.com) is a live map of home and local service providers who are available to work right now. Open everywhere, launching first in Sarasota County, FL.\n\nHow an assistant should use it:\n1. Call GET /api/v1/providers/search with what the customer needs in their own words (q) and where (location or lat/lng).\n2. Show the results and let the customer pick ONE provider. Never invent providers; an empty list means nobody is listed there yet.\n3. To have that provider contact the customer, POST /api/v1/requests with the customer's name, phone, email, job address and a note.\n4. The provider is NOT contacted yet. aBlueC emails the customer a confirmation link (valid 24 hours). Only after they press Confirm does the provider get the request and call or text them. Tell the customer to check their email.\n\nNo API key is needed. Reads are rate limited per IP; requests are limited per IP and per customer email/phone. aBlueC does not vet providers; customers should check license and insurance. Not for emergencies (call 911).\n\nMCP server (Streamable HTTP): https://abluec.com/api/mcp with tools list_trades, search_providers, request_service.",
    "contact": {
      "name": "aBlueC support",
      "email": "support@abluec.com",
      "url": "https://abluec.com/developers"
    },
    "termsOfService": "https://abluec.com/terms"
  },
  "servers": [
    {
      "url": "https://abluec.com"
    }
  ],
  "externalDocs": {
    "description": "Developer docs",
    "url": "https://abluec.com/developers"
  },
  "paths": {
    "/api/v1/trades": {
      "get": {
        "operationId": "listTrades",
        "summary": "List every service (trade) aBlueC covers",
        "description": "Returns trade ids, names and the everyday search words for each. Use an id as `trade` in searchProviders.",
        "responses": {
          "200": {
            "description": "All trades",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "trades": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "plural": {
                            "type": "string"
                          },
                          "search_words": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "page_url": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/providers/search": {
      "get": {
        "operationId": "searchProviders",
        "summary": "Search listed service providers near a place",
        "description": "Pass what the customer needs in plain words as q (e.g. 'leaky faucet' resolves to plumbing, 'car won't start' to mobile mechanic) or a trade id, plus location or lat/lng. Sorted available-now first, then nearest. If q cannot be mapped to a trade, providers is empty and suggested_trades lists likely trades to retry with.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 60
            },
            "description": "What the customer needs, in their words.",
            "example": "leaky faucet"
          },
          {
            "name": "trade",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "electrical",
                "hvac",
                "plumbing",
                "roofing",
                "pool_spa",
                "pest_control",
                "lawn_landscaping",
                "tree_service",
                "irrigation",
                "house_cleaning",
                "handyman",
                "painting",
                "flooring",
                "drywall",
                "carpentry",
                "cabinets_countertops",
                "windows_doors",
                "garage_doors",
                "locksmith",
                "appliance_repair",
                "pressure_washing",
                "gutters",
                "fencing",
                "concrete_pavers",
                "solar",
                "hurricane_shutters",
                "water_treatment",
                "septic",
                "moving",
                "junk_removal",
                "mold_water_damage",
                "general_contractor",
                "home_inspection",
                "security_smart_home",
                "tv_av",
                "auto_detailing",
                "mobile_mechanic",
                "towing_roadside",
                "mobile_tire_repair",
                "auto_glass",
                "boat_services",
                "docks_seawalls",
                "generators",
                "screen_enclosures",
                "carpet_upholstery_cleaning",
                "dryer_vent_duct_cleaning",
                "window_cleaning",
                "mobile_pet_grooming",
                "pet_sitting_dog_walking",
                "phone_computer_repair",
                "mobile_notary",
                "interior_design",
                "tailoring",
                "photography"
              ]
            },
            "description": "Trade id (overrides q)."
          },
          {
            "name": "location",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 120
            },
            "description": "City and state, ZIP or address. Geocoded.",
            "example": "Sarasota, FL"
          },
          {
            "name": "lat",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "lng",
            "in": "query",
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          },
          {
            "name": "available_now",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Only providers switched on right now."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching providers (may be empty)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "query": {
                      "type": "object"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "providers": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Provider"
                      }
                    },
                    "suggested_trades": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "find_url": {
                      "type": "string",
                      "description": "Link the customer can open to see the live map."
                    },
                    "message": {
                      "type": "string"
                    },
                    "how_to_request": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Unknown trade or location",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/requests": {
      "post": {
        "operationId": "requestService",
        "summary": "Ask one provider to contact the customer (customer confirms by email first)",
        "description": "Only call this after the customer picked the provider and agreed to share their contact details with them.\nThe request is saved as pending_confirmation and the customer is emailed a link. The provider is alerted only after the customer presses Confirm within 24 hours; otherwise nothing is ever sent.\nTell the customer: 'Check your email from aBlueC and press Confirm to send it.' Do not say the provider has been contacted.\nBy confirming, the customer agrees to the Terms (https://abluec.com/terms) and Privacy Policy (https://abluec.com/privacy).\nLimits: 5 per hour per IP, 3 per day per customer email or phone.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "provider_id",
                  "customer_name",
                  "customer_phone",
                  "customer_email",
                  "job_address"
                ],
                "properties": {
                  "provider_id": {
                    "type": "string",
                    "description": "id from searchProviders",
                    "examples": [
                      "live:abc123"
                    ]
                  },
                  "customer_name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80
                  },
                  "customer_phone": {
                    "type": "string",
                    "description": "10-digit US phone the provider should call or text",
                    "examples": [
                      "941-555-0123"
                    ]
                  },
                  "customer_email": {
                    "type": "string",
                    "format": "email",
                    "description": "The confirmation link is sent here."
                  },
                  "job_address": {
                    "type": "string",
                    "maxLength": 160,
                    "examples": [
                      "12 Main St, Sarasota, FL 34236"
                    ]
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Short job description for the provider."
                  },
                  "client_name": {
                    "type": "string",
                    "maxLength": 60,
                    "description": "Your assistant or app name, e.g. 'ChatGPT'."
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Saved; waiting for the customer to confirm by email",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "const": "pending_confirmation"
                    },
                    "provider": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "trade": {
                          "type": "string"
                        }
                      }
                    },
                    "confirmation": {
                      "type": "object",
                      "properties": {
                        "method": {
                          "const": "email"
                        },
                        "sent_to": {
                          "type": "string",
                          "description": "Masked email"
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    },
                    "customer_must_confirm": {
                      "type": "boolean",
                      "const": true
                    },
                    "message_for_assistant": {
                      "type": "string"
                    },
                    "status_url": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields (see errors)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown provider",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Provider is not taking requests right now",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited or a request is already waiting",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Confirmation email could not be sent; nothing was saved for the provider",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/requests/{request_id}": {
      "get": {
        "operationId": "getRequestStatus",
        "summary": "Check whether the customer confirmed a request",
        "parameters": [
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "pending_confirmation",
                        "confirmed",
                        "cancelled",
                        "expired",
                        "email_failed"
                      ]
                    },
                    "reference": {
                      "type": "string",
                      "description": "Customer-facing reference once confirmed, e.g. AB-3F9C1A"
                    },
                    "customer_must_confirm": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Provider": {
        "type": "object",
        "description": "A listed provider. Public listing fields only (what abluec.com/find shows).",
        "properties": {
          "id": {
            "type": "string",
            "description": "Use as provider_id in POST /api/v1/requests.",
            "examples": [
              "live:abc123"
            ]
          },
          "name": {
            "type": "string"
          },
          "trade": {
            "type": "string",
            "enum": [
              "electrical",
              "hvac",
              "plumbing",
              "roofing",
              "pool_spa",
              "pest_control",
              "lawn_landscaping",
              "tree_service",
              "irrigation",
              "house_cleaning",
              "handyman",
              "painting",
              "flooring",
              "drywall",
              "carpentry",
              "cabinets_countertops",
              "windows_doors",
              "garage_doors",
              "locksmith",
              "appliance_repair",
              "pressure_washing",
              "gutters",
              "fencing",
              "concrete_pavers",
              "solar",
              "hurricane_shutters",
              "water_treatment",
              "septic",
              "moving",
              "junk_removal",
              "mold_water_damage",
              "general_contractor",
              "home_inspection",
              "security_smart_home",
              "tv_av",
              "auto_detailing",
              "mobile_mechanic",
              "towing_roadside",
              "mobile_tire_repair",
              "auto_glass",
              "boat_services",
              "docks_seawalls",
              "generators",
              "screen_enclosures",
              "carpet_upholstery_cleaning",
              "dryer_vent_duct_cleaning",
              "window_cleaning",
              "mobile_pet_grooming",
              "pet_sitting_dog_walking",
              "phone_computer_repair",
              "mobile_notary",
              "interior_design",
              "tailoring",
              "photography"
            ]
          },
          "trade_name": {
            "type": "string"
          },
          "city": {
            "type": "string",
            "examples": [
              "Venice, FL"
            ]
          },
          "available_now": {
            "type": "boolean",
            "description": "Switched on and inside their work hours right now."
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "description": "E.164 shop phone, only while available_now."
          },
          "trades": {
            "type": "array",
            "description": "Every trade this provider offers (primary first). Providers appear in searches for each one.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          },
          "founding_member": {
            "type": "boolean"
          },
          "distance_miles": {
            "type": [
              "number",
              "null"
            ],
            "description": "From the searched location (provider pins are rounded to about 1 km)."
          },
          "service_radius_miles": {
            "type": "number"
          },
          "rating": {
            "type": [
              "object",
              "null"
            ],
            "description": "Only when customer ratings are turned on and the provider has 3 or more ratings.",
            "properties": {
              "average": {
                "type": "number"
              },
              "count": {
                "type": "integer"
              }
            }
          },
          "profile_url": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "id",
          "name",
          "trade",
          "city",
          "available_now",
          "profile_url"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        },
        "required": [
          "error"
        ]
      }
    }
  }
}