{
  "openapi": "3.1.0",
  "info": {
    "title": "BirdSift API",
    "version": "1.0.0",
    "description": "BirdSift API v1 — list saved leads, run bounded local-business searches, and draft outreach. Human-readable reference: https://www.birdsift.com/docs/api. Agent instructions: https://www.birdsift.com/agent-instructions. Rate limit: 60 requests/minute per API key. Searches and outreach drafts consume workspace credits.",
    "contact": {
      "name": "BirdSift",
      "url": "https://www.birdsift.com/developers"
    }
  },
  "servers": [
    {
      "url": "https://api.birdsift.com"
    }
  ],
  "tags": [
    {
      "name": "docs",
      "description": "Public reference material"
    },
    {
      "name": "leads",
      "description": "Saved workspace leads"
    },
    {
      "name": "searches",
      "description": "Bounded lead discovery"
    },
    {
      "name": "credits",
      "description": "Workspace credit balance"
    }
  ],
  "paths": {
    "/openapi.json": {
      "get": {
        "tags": [
          "docs"
        ],
        "summary": "OpenAPI specification",
        "description": "Returns this OpenAPI 3.1 document for codegen and agent function calling.",
        "operationId": "getOpenApiSpec",
        "security": [],
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 JSON document",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/docs": {
      "get": {
        "tags": [
          "docs"
        ],
        "summary": "API reference (markdown)",
        "description": "Public markdown API reference. No authentication required — use to discover endpoints before calling /v1.",
        "operationId": "getV1Docs",
        "security": [],
        "responses": {
          "200": {
            "description": "Markdown API reference",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/v1/leads": {
      "get": {
        "tags": [
          "leads"
        ],
        "summary": "List saved leads",
        "description": "Returns a cursor-paginated list of leads saved in the authenticated workspace.",
        "operationId": "listLeads",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Page size (1–100)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor from a previous response's next_cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "Lead page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeadListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid query",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited (60 requests/minute per key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/leads/{id}": {
      "get": {
        "tags": [
          "leads"
        ],
        "summary": "Get one saved lead",
        "description": "Fetch a single lead by UUID, including website audit flags used for outreach.",
        "operationId": "getLead",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Lead UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lead detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeadDetail"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Lead not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/credits": {
      "get": {
        "tags": [
          "credits"
        ],
        "summary": "Get credit balance",
        "description": "Returns the remaining credit balance for the authenticated workspace.",
        "operationId": "getCredits",
        "responses": {
          "200": {
            "description": "Current balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/searches": {
      "post": {
        "tags": [
          "searches"
        ],
        "summary": "Run a bounded search and save results",
        "description": "Queries Google Places for local businesses matching trade + location filters, verifies websites, saves matches as workspace leads, and debits credits.",
        "operationId": "createSearch",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Search results saved as leads",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited (60 requests/minute per key)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/leads/{id}/outreach-draft": {
      "post": {
        "tags": [
          "leads"
        ],
        "summary": "Draft outreach email for a saved lead",
        "description": "Generates a fact-based cold email draft for a saved lead using verified Google Places and website audit data.",
        "operationId": "draftOutreach",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Lead UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OutreachDraftRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Draft email",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OutreachDraftResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Insufficient audit data to draft outreach",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Machine-readable error code"
              },
              "message": {
                "type": "string",
                "description": "Human-readable error message"
              }
            }
          }
        }
      },
      "LeadSummary": {
        "type": "object",
        "required": [
          "id",
          "place_id",
          "name",
          "category",
          "address",
          "website",
          "email",
          "outreach_status",
          "added_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "BirdSift lead UUID"
          },
          "place_id": {
            "type": "string",
            "description": "Google Places ID"
          },
          "name": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "description": "Business category or trade"
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "website": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "outreach_status": {
            "type": "string",
            "description": "Draft / sent / skipped state"
          },
          "added_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LeadDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LeadSummary"
          },
          {
            "type": "object",
            "required": [
              "no_website_flag",
              "not_mobile_friendly_flag",
              "outdated_website_flag"
            ],
            "properties": {
              "no_website_flag": {
                "type": "boolean",
                "nullable": true
              },
              "not_mobile_friendly_flag": {
                "type": "boolean",
                "nullable": true
              },
              "outdated_website_flag": {
                "type": "boolean",
                "nullable": true
              }
            }
          }
        ]
      },
      "LeadListResponse": {
        "type": "object",
        "required": [
          "leads",
          "next_cursor"
        ],
        "properties": {
          "leads": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LeadSummary"
            }
          },
          "next_cursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass as ?cursor= on the next page"
          }
        }
      },
      "CreditsResponse": {
        "type": "object",
        "required": [
          "balance"
        ],
        "properties": {
          "balance": {
            "type": "integer",
            "description": "Remaining workspace credits"
          }
        }
      },
      "SearchQuery": {
        "type": "object",
        "required": [
          "location",
          "category"
        ],
        "properties": {
          "location": {
            "type": "string",
            "description": "City or region, e.g. Austin, TX"
          },
          "category": {
            "type": "string",
            "description": "Trade or business type, e.g. dentist"
          }
        }
      },
      "SearchFilters": {
        "type": "object",
        "properties": {
          "min_rating": {
            "type": "number",
            "description": "Minimum Google rating (0–5)"
          },
          "no_website": {
            "type": "boolean",
            "description": "Only businesses with no website"
          },
          "not_mobile_friendly": {
            "type": "boolean",
            "description": "Only non-mobile-friendly sites"
          },
          "outdated_website": {
            "type": "boolean",
            "description": "Only outdated-looking sites"
          }
        }
      },
      "SearchRequest": {
        "type": "object",
        "required": [
          "queries",
          "max_results"
        ],
        "properties": {
          "queries": {
            "type": "array",
            "minItems": 1,
            "maxItems": 5,
            "items": {
              "$ref": "#/components/schemas/SearchQuery"
            }
          },
          "filters": {
            "$ref": "#/components/schemas/SearchFilters"
          },
          "max_results": {
            "type": "integer",
            "minimum": 1,
            "maximum": 25,
            "description": "Maximum leads to return across all queries"
          }
        }
      },
      "SearchResultLead": {
        "allOf": [
          {
            "$ref": "#/components/schemas/LeadSummary"
          },
          {
            "type": "object",
            "properties": {
              "has_website": {
                "type": "boolean",
                "nullable": true
              },
              "is_mobile_friendly": {
                "type": "boolean",
                "nullable": true
              },
              "is_outdated": {
                "type": "boolean",
                "nullable": true
              }
            }
          }
        ]
      },
      "SearchResponse": {
        "type": "object",
        "required": [
          "results",
          "credits_spent",
          "truncated"
        ],
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SearchResultLead"
            }
          },
          "credits_spent": {
            "type": "integer",
            "description": "Credits consumed by this search"
          },
          "truncated": {
            "type": "boolean",
            "description": "True when max_results capped the result set"
          }
        }
      },
      "OutreachDraftRequest": {
        "type": "object",
        "properties": {
          "locale": {
            "type": "string",
            "enum": [
              "en",
              "fr"
            ],
            "description": "Draft language"
          }
        }
      },
      "OutreachDraftResponse": {
        "type": "object",
        "required": [
          "subject",
          "body",
          "facts_used"
        ],
        "properties": {
          "subject": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "facts_used": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Verified facts referenced in the draft"
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Workspace API key (`bsk_live_…`). Create from the app."
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "Supabase OAuth 2.0 access token for workspace-scoped MCP access. Metadata: GET /.well-known/oauth-authorization-server",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://tzngbfxhkxvbtoxsypii.supabase.co/auth/v1/oauth/authorize",
            "tokenUrl": "https://tzngbfxhkxvbtoxsypii.supabase.co/auth/v1/oauth/token",
            "scopes": {
              "email": "Email address",
              "profile": "Basic profile"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "ApiKeyAuth": []
    }
  ]
}
