{
  "openapi": "3.1.0",
  "info": {
    "title": "disburse API",
    "version": "1.0.0",
    "description": "Lead discovery, enrichment, and verification. One plain-English query returns a ranked, structured list of the companies and people that fit; single records can be resolved and filled across sources; emails and phones can be validated offline.\n\nEvery endpoint is a `POST` under `/v1` and authenticated with a bearer API key (`Authorization: Bearer sk_live_…`). All request and response bodies are JSON.",
    "contact": {
      "name": "disburse support",
      "url": "https://disburse.dev"
    }
  },
  "servers": [
    {
      "url": "https://api.disburse.dev",
      "description": "disburse API"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Search",
      "description": "Find people and companies from a natural-language query or structured filters. Results are ranked and cursor-paginated."
    },
    {
      "name": "Enrich",
      "description": "Resolve a known identifier (email, LinkedIn URL, domain) into more data: a single field, a full merged record, or a batch."
    },
    {
      "name": "Verify",
      "description": "Validate an email address or phone number and return the component signals behind the verdict."
    }
  ],
  "paths": {
    "/v1/search/people": {
      "post": {
        "tags": [
          "Search"
        ],
        "summary": "Search people",
        "operationId": "searchPersons",
        "x-openai-isConsequential": false,
        "description": "Provide exactly one of `query` (natural language) or `filters` (structured). Results are ranked; page via `next_cursor`, or pass `count` (1-500) for a whole deduplicated list in one call. Costs 1 credit per NEW lead (row with email/phone), rest free; `summary.billing` reports it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchRequest"
              },
              "examples": {
                "natural": {
                  "summary": "Natural-language query",
                  "value": {
                    "query": "heads of growth at Series B fintechs in Australia",
                    "limit": 5
                  }
                },
                "filters": {
                  "summary": "Structured filters",
                  "value": {
                    "filters": {
                      "seniority": [
                        "vp",
                        "executive"
                      ],
                      "job_function": [
                        "Marketing"
                      ],
                      "location": {
                        "country": "AU"
                      },
                      "top_per_company": true
                    },
                    "limit": 5
                  }
                },
                "paginate": {
                  "summary": "Next page",
                  "value": {
                    "cursor": "eyJhIjpbMTcwMDAwMDAwMF0sInEiOnsuLi59fQ=="
                  }
                },
                "fulfil": {
                  "summary": "Whole list in one call",
                  "value": {
                    "query": "founders in Australia",
                    "count": 200,
                    "quality_bar": "balanced"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked matches",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                },
                "example": {
                  "interpreted": {
                    "entity": "person",
                    "filters": {
                      "seniority": [
                        "vp",
                        "executive"
                      ],
                      "job_function": [
                        "Marketing"
                      ],
                      "location": {
                        "country": "AU"
                      },
                      "top_per_company": true
                    },
                    "limit": 5
                  },
                  "results": [
                    {
                      "id": "psn_9f2a1c3e5b7d8a90",
                      "name": "Ada Lovelace",
                      "email": "ada@acme.com",
                      "cellphone": "+61 400 000 000",
                      "title": "VP of Growth",
                      "seniority": "vp",
                      "role_started": "2024-03-01",
                      "last_observed_at": "2026-09-14",
                      "email_status": "verified",
                      "email_last_verified_at": "2026-07-28",
                      "company_about_us": "Acme builds billing infrastructure for APAC marketplaces.",
                      "linkedin_url": "https://linkedin.com/in/adalovelace",
                      "company_domain": "acme.com",
                      "city": "Sydney",
                      "region": "NSW",
                      "country": "AU",
                      "job_function": "Marketing",
                      "seniority_rank": 4,
                      "company_industry": "software",
                      "company_employees": 220,
                      "company_entity_type": "Privately Held",
                      "company_country": "AU",
                      "company_tech": [
                        "salesforce",
                        "aws"
                      ],
                      "signals": [
                        "hiring"
                      ]
                    }
                  ],
                  "total": 128,
                  "next_cursor": "eyJhIjpbMTcwMDAwMDAwMF0sInEiOnsuLi59fQ=="
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          }
        }
      }
    },
    "/v1/search/companies": {
      "post": {
        "tags": [
          "Search"
        ],
        "summary": "Search companies",
        "operationId": "searchCompanys",
        "x-openai-isConsequential": false,
        "description": "Provide exactly one of `query` (natural language) or `filters` (structured). Results are ranked; page via `next_cursor`, or pass `count` (1-500) for a whole deduplicated list in one call. Costs 1 credit per NEW lead (row with email/phone), rest free; `summary.billing` reports it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchRequest"
              },
              "examples": {
                "natural": {
                  "summary": "Natural-language query",
                  "value": {
                    "query": "Series B fintech companies in Australia that are hiring engineers",
                    "limit": 5
                  }
                },
                "filters": {
                  "summary": "Structured filters",
                  "value": {
                    "filters": {
                      "industry": [
                        "software"
                      ],
                      "employees": {
                        "gte": 50,
                        "lte": 500
                      },
                      "location": {
                        "country": "AU"
                      },
                      "signals": [
                        "recent_funding"
                      ]
                    },
                    "limit": 5
                  }
                },
                "paginate": {
                  "summary": "Next page",
                  "value": {
                    "cursor": "eyJhIjpbMTcwMDAwMDAwMF0sInEiOnsuLi59fQ=="
                  }
                },
                "fulfil": {
                  "summary": "Whole list in one call",
                  "value": {
                    "query": "Series B fintech companies in Australia that are hiring engineers",
                    "count": 100,
                    "quality_bar": "strict"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked matches",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                },
                "example": {
                  "interpreted": {
                    "entity": "company",
                    "filters": {
                      "industry": [
                        "software"
                      ],
                      "employees": {
                        "gte": 50,
                        "lte": 500
                      },
                      "location": {
                        "country": "AU"
                      },
                      "signals": [
                        "recent_funding"
                      ]
                    },
                    "limit": 5
                  },
                  "results": [
                    {
                      "id": "cmp_1a2b3c4d5e6f7a80",
                      "domain": "acme.com",
                      "name": "Acme Inc",
                      "city": "Sydney",
                      "region": "NSW",
                      "country": "AU",
                      "industry": "software",
                      "employees": 220,
                      "revenue": 25000000,
                      "naics": [
                        "5112",
                        "51",
                        "511"
                      ],
                      "specialties": [
                        "payments",
                        "developer tools"
                      ],
                      "entity_type": "Privately Held",
                      "employee_range": "201 to 500",
                      "year_founded": 2018,
                      "signals": [
                        "recent_funding",
                        "hiring"
                      ]
                    }
                  ],
                  "total": 42,
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "$ref": "#/components/responses/Unprocessable"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          }
        }
      }
    },
    "/v1/enrich/linkedin-to-email": {
      "post": {
        "tags": [
          "Enrich"
        ],
        "summary": "LinkedIn → email",
        "operationId": "enrichLinkedInToEmail",
        "x-openai-isConsequential": false,
        "description": "First matching source wins. The resolved fields are returned flat, with `confidence` and `source`. Costs 1 credit when the result carries an email or phone new to your org; otherwise free.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "linkedin_url"
                ],
                "properties": {
                  "linkedin_url": {
                    "type": "string",
                    "example": "https://linkedin.com/in/adalovelace"
                  }
                }
              },
              "example": {
                "linkedin_url": "https://linkedin.com/in/adalovelace"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resolved fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrichFieldResult"
                },
                "example": {
                  "email": "ada@acme.com",
                  "confidence": 0.92,
                  "source": "revenuebase"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          }
        }
      }
    },
    "/v1/enrich/email-to-linkedin": {
      "post": {
        "tags": [
          "Enrich"
        ],
        "summary": "Email → LinkedIn",
        "operationId": "enrichEmailToLinkedIn",
        "x-openai-isConsequential": false,
        "description": "First matching source wins. The resolved fields are returned flat, with `confidence` and `source`. Costs 1 credit when the result carries an email or phone new to your org; otherwise free.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "example": "ada@acme.com"
                  }
                }
              },
              "example": {
                "email": "ada@acme.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resolved fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrichFieldResult"
                },
                "example": {
                  "linkedin_url": "https://linkedin.com/in/adalovelace",
                  "confidence": 0.88,
                  "source": "linkedin"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          }
        }
      }
    },
    "/v1/enrich/reverse-email": {
      "post": {
        "tags": [
          "Enrich"
        ],
        "summary": "Email → person",
        "operationId": "enrichReverseEmail",
        "x-openai-isConsequential": false,
        "description": "Fills every field the lead has across all sources, merged into one record. Costs 1 credit when the result carries an email or phone new to your org; otherwise free.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "example": "ada@acme.com"
                  }
                }
              },
              "example": {
                "email": "ada@acme.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Merged record",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrichMergeResult"
                },
                "example": {
                  "fields": {
                    "id": "psn_9f2a1c3e5b7d8a90",
                    "name": "Ada Lovelace",
                    "email": "ada@acme.com",
                    "cellphone": "+61 400 000 000",
                    "title": "VP of Growth",
                    "seniority": "vp",
                    "role_started": "2024-03-01",
                    "last_observed_at": "2026-09-14",
                    "email_status": "verified",
                    "email_last_verified_at": "2026-07-28",
                    "company_about_us": "Acme builds billing infrastructure for APAC marketplaces.",
                    "linkedin_url": "https://linkedin.com/in/adalovelace",
                    "company_domain": "acme.com",
                    "city": "Sydney",
                    "region": "NSW",
                    "country": "AU",
                    "job_function": "Marketing",
                    "seniority_rank": 4,
                    "company_industry": "software",
                    "company_employees": 220,
                    "company_entity_type": "Privately Held",
                    "company_country": "AU",
                    "company_tech": [
                      "salesforce",
                      "aws"
                    ],
                    "signals": [
                      "hiring"
                    ]
                  },
                  "sources": [
                    "revenuebase",
                    "linkedin"
                  ],
                  "verified": true,
                  "verification": {
                    "email": {
                      "valid": true,
                      "signals": {
                        "syntax": true,
                        "domain": "acme.com",
                        "has_mx": true,
                        "disposable": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          }
        }
      }
    },
    "/v1/enrich/reverse-linkedin": {
      "post": {
        "tags": [
          "Enrich"
        ],
        "summary": "LinkedIn → person",
        "operationId": "enrichReverseLinkedIn",
        "x-openai-isConsequential": false,
        "description": "Fills every field the lead has across all sources, merged into one record. Costs 1 credit when the result carries an email or phone new to your org; otherwise free.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "linkedin_url"
                ],
                "properties": {
                  "linkedin_url": {
                    "type": "string",
                    "example": "https://linkedin.com/in/adalovelace"
                  }
                }
              },
              "example": {
                "linkedin_url": "https://linkedin.com/in/adalovelace"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Merged record",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrichMergeResult"
                },
                "example": {
                  "fields": {
                    "id": "psn_9f2a1c3e5b7d8a90",
                    "name": "Ada Lovelace",
                    "email": "ada@acme.com",
                    "cellphone": "+61 400 000 000",
                    "title": "VP of Growth",
                    "seniority": "vp",
                    "role_started": "2024-03-01",
                    "last_observed_at": "2026-09-14",
                    "email_status": "verified",
                    "email_last_verified_at": "2026-07-28",
                    "company_about_us": "Acme builds billing infrastructure for APAC marketplaces.",
                    "linkedin_url": "https://linkedin.com/in/adalovelace",
                    "company_domain": "acme.com",
                    "city": "Sydney",
                    "region": "NSW",
                    "country": "AU",
                    "job_function": "Marketing",
                    "seniority_rank": 4,
                    "company_industry": "software",
                    "company_employees": 220,
                    "company_entity_type": "Privately Held",
                    "company_country": "AU",
                    "company_tech": [
                      "salesforce",
                      "aws"
                    ],
                    "signals": [
                      "hiring"
                    ]
                  },
                  "sources": [
                    "revenuebase",
                    "linkedin"
                  ],
                  "verified": true,
                  "verification": {
                    "email": {
                      "valid": true,
                      "signals": {
                        "syntax": true,
                        "domain": "acme.com",
                        "has_mx": true,
                        "disposable": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          }
        }
      }
    },
    "/v1/enrich/person": {
      "post": {
        "tags": [
          "Enrich"
        ],
        "summary": "Contact by LinkedIn URL",
        "operationId": "enrichPerson",
        "x-openai-isConsequential": false,
        "description": "Complete a business contact from their LinkedIn URL (any pasted form). `columns` as in search; a list without contact fields is a free preview. 1 credit only for a contact new to your org. `waterfall` runs the waterfall for a missing contact (1 waterfall credit per email, 10 per mobile).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "linkedin_url"
                ],
                "properties": {
                  "linkedin_url": {
                    "type": "string",
                    "example": "https://www.linkedin.com/in/adalovelace"
                  },
                  "columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Fields to return. Omit for the default lead row. `location` and `company_location` are composed `City, Region, Country`.",
                    "example": [
                      "name",
                      "title",
                      "company_name",
                      "location",
                      "has_email",
                      "has_phone"
                    ]
                  },
                  "hints": {
                    "type": "object",
                    "description": "What you can read off the profile page. People rename their LinkedIn slug, so when the URL misses, the name settles it and company/location break ties. A hit this way carries `matched_by: \"name\"`; an ambiguous name is a 404, never a guess.",
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Ada Lovelace"
                      },
                      "company": {
                        "type": "string",
                        "example": "Acme Billing"
                      },
                      "location": {
                        "type": "string",
                        "example": "Sydney, New South Wales, Australia"
                      }
                    }
                  },
                  "waterfall": {
                    "type": "string",
                    "enum": [
                      "email",
                      "mobile",
                      "both"
                    ],
                    "description": "Run the waterfall for the contact disburse's own data lacks. Own data is always used first and never spends waterfall credits. Spends the org's separate waterfall credits (1 per email, 10 per mobile) only when a contact is found; an email is withheld (still charged) when the waterfall finds the person at a different employer. The response's `waterfall` block says what happened per field."
                  }
                }
              },
              "example": {
                "linkedin_url": "https://www.linkedin.com/in/adalovelace"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Person record",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Person"
                },
                "example": {
                  "id": "psn_9f2a1c3e5b7d8a90",
                  "name": "Ada Lovelace",
                  "email": "ada@acme.com",
                  "cellphone": "+61 400 000 000",
                  "title": "VP of Growth",
                  "seniority": "vp",
                  "role_started": "2024-03-01",
                  "last_observed_at": "2026-09-14",
                  "email_status": "verified",
                  "email_last_verified_at": "2026-07-28",
                  "company_about_us": "Acme builds billing infrastructure for APAC marketplaces.",
                  "linkedin_url": "https://linkedin.com/in/adalovelace",
                  "company_domain": "acme.com",
                  "city": "Sydney",
                  "region": "NSW",
                  "country": "AU",
                  "job_function": "Marketing",
                  "seniority_rank": 4,
                  "company_industry": "software",
                  "company_employees": 220,
                  "company_entity_type": "Privately Held",
                  "company_country": "AU",
                  "company_tech": [
                    "salesforce",
                    "aws"
                  ],
                  "signals": [
                    "hiring"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          }
        }
      }
    },
    "/v1/enrich/company": {
      "post": {
        "tags": [
          "Enrich"
        ],
        "summary": "Company by domain",
        "operationId": "enrichCompany",
        "x-openai-isConsequential": false,
        "description": "Look up a company's firmographics and signals from the index by domain.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "example": "acme.com"
                  }
                }
              },
              "example": {
                "domain": "acme.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Company record",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                },
                "example": {
                  "id": "cmp_1a2b3c4d5e6f7a80",
                  "domain": "acme.com",
                  "name": "Acme Inc",
                  "city": "Sydney",
                  "region": "NSW",
                  "country": "AU",
                  "industry": "software",
                  "employees": 220,
                  "revenue": 25000000,
                  "naics": [
                    "5112",
                    "51",
                    "511"
                  ],
                  "specialties": [
                    "payments",
                    "developer tools"
                  ],
                  "entity_type": "Privately Held",
                  "employee_range": "201 to 500",
                  "year_founded": 2018,
                  "signals": [
                    "recent_funding",
                    "hiring"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "504": {
            "$ref": "#/components/responses/Timeout"
          }
        }
      }
    },
    "/v1/enrich/batch": {
      "post": {
        "tags": [
          "Enrich"
        ],
        "summary": "Batch enrich",
        "operationId": "enrichBatch",
        "x-openai-isConsequential": false,
        "description": "Run one enrichment `operation` over 1–100 `inputs` in a single call. Results come back in input order; an input that can't be resolved (or is missing its field) is `null` (or an `{ error }` object for a missing field) rather than failing the whole batch.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchRequest"
              },
              "example": {
                "operation": "email_to_linkedin",
                "inputs": [
                  {
                    "email": "ada@acme.com"
                  },
                  {
                    "email": "grace@globex.com"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-input results, in input order",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResponse"
                },
                "example": {
                  "results": [
                    {
                      "linkedin_url": "https://linkedin.com/in/adalovelace",
                      "confidence": 0.88,
                      "source": "linkedin"
                    },
                    null
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/exports": {
      "post": {
        "tags": [
          "Search"
        ],
        "summary": "Start a bulk export",
        "operationId": "startExport",
        "x-openai-isConsequential": false,
        "description": "Start a server-side CSV export of up to 25,000 rows. Returns at once with the real pool and file size, before any work happens; poll `/v1/exports/{id}/file` for the CSV. Costs 1 credit per NEW lead in the file (row with email/phone); already-received leads and contact-free rows are free.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "target"
                ],
                "properties": {
                  "entity": {
                    "type": "string",
                    "enum": [
                      "person",
                      "company"
                    ],
                    "description": "Defaults to `person`."
                  },
                  "query": {
                    "type": "string",
                    "description": "Natural-language description of who to export."
                  },
                  "filters": {
                    "$ref": "#/components/schemas/Filters"
                  },
                  "sort": {
                    "type": "array",
                    "description": "Same shape as a search `sort`.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "field": {
                          "type": "string"
                        },
                        "desc": {
                          "type": "boolean"
                        }
                      }
                    }
                  },
                  "target": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 25000,
                    "description": "How many rows to export."
                  },
                  "columns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Row width. Omit for **every** available column (~85) — exports are files, so full width is free. Or name them: `[\"name\",\"email\",\"direct_phone\",\"location\"]`. `location` and `company_location` are composed `City, Region, Country`. Unknown names are rejected with the full available list."
                  }
                }
              },
              "examples": {
                "natural": {
                  "summary": "Natural language",
                  "value": {
                    "query": "founders in Australia with emails",
                    "target": 5000
                  }
                },
                "columns": {
                  "summary": "Chosen columns",
                  "value": {
                    "query": "marketing directors in Sydney",
                    "target": 2000,
                    "columns": [
                      "name",
                      "title",
                      "email",
                      "company_name",
                      "location"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Export started and priced",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportJob"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/v1/exports/{id}": {
      "get": {
        "tags": [
          "Search"
        ],
        "summary": "Export status",
        "operationId": "getExport",
        "x-openai-isConsequential": false,
        "description": "Current progress of an export job. Exports expire 24 hours after creation.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The export id returned by `POST /v1/exports`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Job state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportJob"
                }
              }
            }
          },
          "404": {
            "description": "Unknown or expired export"
          }
        }
      }
    },
    "/v1/exports/{id}/file": {
      "get": {
        "tags": [
          "Search"
        ],
        "summary": "Fetch the export file",
        "operationId": "getExportFile",
        "x-openai-isConsequential": false,
        "description": "Returns the finished CSV (`200`, `text/csv`), or `202` with job state and `Retry-After` while rendering; poll the same URL until the file arrives. Each call advances the render up to ~35s. The CSV is Excel-safe: UTF-8 BOM, CRLF, and formula-risk cells neutralized.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The export id returned by `POST /v1/exports`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The complete CSV. ChatGPT receives it as attached files instead, since a CSV this size cannot survive an action response intact; the files arrive in the conversation like an upload and are readable from code.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              },
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "openaiFileResponse": {
                      "type": "array",
                      "description": "The CSV as attached files, split only if the row count demands it.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "mime_type": {
                            "type": "string"
                          },
                          "content": {
                            "type": "string",
                            "format": "byte"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Still rendering — poll again",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportJob"
                }
              }
            }
          },
          "404": {
            "description": "Unknown or expired export"
          }
        }
      }
    },
    "/v1/exports/{id}/chunk/{n}": {
      "get": {
        "tags": [
          "Search"
        ],
        "summary": "Fetch one export chunk",
        "operationId": "getExportChunk",
        "x-openai-isConsequential": false,
        "description": "One bounded piece of the export (~500 rows, capped by size), for very large files or resumable clients. Chunks render in order and are idempotent: re-fetching chunk `n` returns identical bytes, so a dropped connection can never corrupt a file. Only chunk 0 carries the header row.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The export id returned by `POST /v1/exports`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "n",
            "in": "path",
            "required": true,
            "description": "0-based chunk number.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One chunk",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "csv": {
                      "type": "string"
                    },
                    "chunk": {
                      "type": "integer"
                    },
                    "rows": {
                      "type": "integer"
                    },
                    "progress": {
                      "$ref": "#/components/schemas/ExportJob"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Chunks render in order; fetch the next unrendered chunk"
          }
        }
      }
    },
    "/v1/account": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Account credits",
        "operationId": "getAccount",
        "x-openai-isConsequential": false,
        "description": "How many credits do I have: the account's live credit balance, whether leads can still be received, and the monthly reset date. Free to call. 1 credit = 1 lead delivered with an email or phone; searching and verifying are always free.",
        "responses": {
          "200": {
            "description": "The account's credit state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "credits_remaining": {
                      "description": "Credits left this cycle, or the string 'unlimited' on unlimited plans."
                    },
                    "credits_granted": {
                      "type": "number",
                      "description": "Credits granted per cycle. Absent on unlimited plans."
                    },
                    "resets_at": {
                      "type": "string",
                      "description": "UTC date the balance refills, e.g. 2026-09-19."
                    },
                    "can_receive_leads": {
                      "type": "boolean",
                      "description": "False when the balance is empty and lead delivery is paused."
                    },
                    "pricing": {
                      "type": "string",
                      "description": "What one credit buys."
                    },
                    "waterfall_credits_remaining": {
                      "description": "Waterfall credits left this month (the separate balance the waterfall draws on), or 'unlimited'."
                    },
                    "waterfall_pricing": {
                      "type": "string",
                      "description": "What one waterfall credit buys."
                    },
                    "manage": {
                      "type": "string",
                      "description": "URL of the billing page."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/verify/{field}": {
      "post": {
        "tags": [
          "Verify"
        ],
        "summary": "Verify a field",
        "operationId": "verifyField",
        "x-openai-isConsequential": false,
        "description": "Validate one field: `email` (syntax, disposable list, live MX) or `phone` (libphonenumber format). Email `valid` means the domain accepts mail, NOT that the mailbox exists: never send to a guessed address on this alone. Phone is never dialed. `summary`/`not_checked` state what was not verified.",
        "parameters": [
          {
            "name": "field",
            "in": "path",
            "required": true,
            "description": "What to verify.",
            "schema": {
              "type": "string",
              "enum": [
                "email",
                "phone"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "The value to verify, under its field name or the generic `value` key.",
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "value": {
                    "type": "string"
                  }
                }
              },
              "examples": {
                "email": {
                  "summary": "Email",
                  "value": {
                    "email": "ada@acme.com"
                  }
                },
                "phone": {
                  "summary": "Phone",
                  "value": {
                    "phone": "+61 2 1234 5678"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verdict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyResponse"
                },
                "examples": {
                  "email": {
                    "summary": "Email verdict (domain-level, not a mailbox check)",
                    "value": {
                      "field": "email",
                      "value": "ada@acme.com",
                      "valid": true,
                      "signals": {
                        "syntax": true,
                        "domain": "acme.com",
                        "has_mx": true,
                        "disposable": false,
                        "mailbox_verified": false,
                        "catch_all": "unknown"
                      },
                      "summary": "Domain-level checks only (syntax, disposable list, MX). valid:true means the domain can receive mail, not that this mailbox exists.",
                      "not_checked": [
                        "mailbox_exists: the domain accepts mail, but this check cannot tell whether this specific address does; an invented address at this domain would score the same",
                        "catch_all: if the domain accepts every address, no domain-level check can flag a bad local part"
                      ]
                    }
                  },
                  "phone": {
                    "summary": "Phone verdict",
                    "value": {
                      "field": "phone",
                      "value": "+61 2 1234 5678",
                      "valid": true,
                      "signals": {
                        "type": "fixed_line",
                        "region": "AU",
                        "e164": "+61212345678"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "501": {
            "$ref": "#/components/responses/NotImplemented"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your API key, sent as `Authorization: Bearer sk_live_…`."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Malformed body, missing field, or an invalid filter/cursor (`invalid_request`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key (`unauthorized`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No matching record for the given identifier (`no_data`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InsufficientCredits": {
        "description": "The organization is out of credits (`insufficient_credits`); top up or upgrade in the dashboard.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unprocessable": {
        "description": "The natural-language query couldn't be parsed or compiled (`unparseable_query`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded (`rate_limited`); see the `Retry-After` header and `error.retry_after`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unavailable": {
        "description": "Sources are temporarily unavailable (`unavailable`); retry after `error.retry_after` seconds.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Timeout": {
        "description": "The request exceeded its deadline (`timeout`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotImplemented": {
        "description": "Verification is not configured on this deployment.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "SearchRequest": {
        "type": "object",
        "description": "Provide exactly one of `query` or `filters` (or a `cursor` to page an earlier search).",
        "properties": {
          "query": {
            "type": "string",
            "description": "Natural-language query. The model parses it into filters; omit `filters` when using this."
          },
          "filters": {
            "$ref": "#/components/schemas/Filters",
            "description": "Structured filters, applied as-is. Omit `query` when using this."
          },
          "limit": {
            "type": "integer",
            "default": 25,
            "minimum": 1,
            "description": "Page size (max results)."
          },
          "cursor": {
            "type": "string",
            "description": "Opaque pagination cursor from a previous response's `next_cursor`. Reuses that query verbatim."
          },
          "count": {
            "type": "integer",
            "minimum": 1,
            "maximum": 25000,
            "description": "Target number of results to fulfil in ONE call. The server owns pagination, deduplication and quality filtering, and the response carries a `summary` (composition per tier, what was excluded, and a mandatory stop reason) plus a `match_tier` on every row. Use this instead of cursor-walking for 'give me N …' requests; incompatible with `cursor` and `top_per_company`. Counts above 500 (up to 25,000) automatically become an export job: the response is `202` with `export_started`, the job, and a `Location` header — poll `/v1/exports/{id}/file` until it returns `text/csv` (a `202` reply carries progress)."
          },
          "quality_bar": {
            "type": "string",
            "enum": [
              "strict",
              "balanced",
              "broad"
            ],
            "description": "With `count`: `strict` returns only high-confidence matches and may under-fill honestly; `balanced` (default) returns strict matches first then clearly-labeled lower-confidence backfill; `broad` returns ranked results only."
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "With `count`: which fields each row carries. Omit for the lead-list default (~18 fields); `[\"*\"]` for every available field (capped at count 100 - full rows are ~10x heavier); or an explicit list such as `[\"name\",\"email\",\"direct_phone\",\"skills\",\"company_revenue\"]`. `location` and `company_location` are composed `City, Region, Country`. Unknown names are rejected with the full available list in the error."
          }
        }
      },
      "ExportJob": {
        "type": "object",
        "description": "A bulk export job. Exports live 24 hours.",
        "properties": {
          "id": {
            "type": "string",
            "example": "exp_9e2f335d2ce9bc2d"
          },
          "entity": {
            "type": "string",
            "enum": [
              "person",
              "company"
            ]
          },
          "target": {
            "type": "integer",
            "description": "Rows requested."
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "estimated_total": {
            "type": "integer",
            "description": "The real size of the matching pool."
          },
          "estimated_bytes": {
            "type": "integer",
            "description": "Approximate file size."
          },
          "interpretation": {
            "type": "string",
            "description": "Plain-English reading of the query being exported."
          },
          "delivered": {
            "type": "integer",
            "description": "Rows rendered so far."
          },
          "rendered_chunks": {
            "type": "integer"
          },
          "quarantined": {
            "type": "integer",
            "description": "Rows dropped as junk (placeholder names)."
          },
          "done": {
            "type": "boolean"
          },
          "stopped_reason": {
            "type": "string",
            "enum": [
              "target_reached",
              "results_exhausted"
            ],
            "description": "`results_exhausted` means the pool ran out before the target — the count is honest, not padded."
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Anything the engine changed about the query."
          },
          "expires": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Filters": {
        "type": "object",
        "description": "The closed set of filterable fields. Strings in keyword sets are matched ANY-of.",
        "properties": {
          "location": {
            "$ref": "#/components/schemas/GeoFilter"
          },
          "revenue": {
            "$ref": "#/components/schemas/RangeFilter",
            "description": "Company annual revenue (USD)."
          },
          "employees": {
            "$ref": "#/components/schemas/RangeFilter",
            "description": "Company headcount."
          },
          "industry": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Industry labels (ANY-of)."
          },
          "title": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Job titles (ANY-of)."
          },
          "seniority": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Seniority band (ANY-of). Exactly five exist: `individual`, `manager`, `director`, `vp`, `executive`. Spoken forms are mapped (`c-level`/`founder` -> `executive`, `head` -> `director`, `associate`/`staff` -> `individual`); there is no senior/junior band, so put those words in `keywords` instead."
          },
          "signals": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Intent/timing tags (ANY-of). The company set is `hiring`, `funded`, `recent_funding`, `high_growth`, `mobile_app`, `web_app`, `has_ciso`, `has_cio`. Unknown values are not silently ignored: they are reported in `relaxed` and searched as text instead, which ranks rather than narrows."
          },
          "keywords": {
            "type": "string",
            "description": "Free-text keyword match. Keywords RANK results rather than narrowing them, so `total` counts the structured filters alone — `strong_matches` in the response is the count that clearly match the keywords."
          },
          "strict": {
            "type": "boolean",
            "description": "Narrow the result SET to records clearly matching `keywords` (the `strong_matches` core; measured high-confidence, not a guarantee). Requires `keywords`. For building lists, prefer `count` + `quality_bar` which layers this automatically."
          },
          "expand": {
            "type": "boolean",
            "description": "Opt in to semantic recall: results may also match by meaning, not just exact classification (e.g. include companies not classified under the industry you named, ranked after exact matches). Off by default — it trades precision for recall."
          },
          "naics": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "NAICS codes or prefixes (ANY-of)."
          },
          "entity_type": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Company entity type, e.g. `Privately Held`, `Public Company` (ANY-of)."
          },
          "locations": {
            "$ref": "#/components/schemas/RangeFilter",
            "description": "Range over a company's number of physical locations."
          },
          "specialties": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Matched against company specialties / about text."
          },
          "tech": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Detected tech stack a company uses, e.g. `salesforce`, `hubspot`, `aws` (ANY-of). On a people search this matches the employer's stack. Sparse (~1% of companies) — use only when a tool is named."
          },
          "job_function": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Person department/function, e.g. `Sales`, `Marketing`, `Human Resources` (ANY-of)."
          },
          "top_per_company": {
            "type": "boolean",
            "description": "People search only: collapse to the single most-senior person per company."
          },
          "has_email": {
            "type": "boolean",
            "description": "People search only: keep only people with a verified email. Most records have no email (~10%), so apply only when reachable contacts are required."
          },
          "has_phone": {
            "type": "boolean",
            "description": "People search only: keep only people with a cellphone or direct dial."
          }
        }
      },
      "RangeFilter": {
        "type": "object",
        "description": "An inclusive numeric range; either bound may be omitted.",
        "properties": {
          "gte": {
            "type": "number"
          },
          "lte": {
            "type": "number"
          }
        }
      },
      "GeoFilter": {
        "type": "object",
        "description": "Narrow by geography.",
        "properties": {
          "city": {
            "type": "string"
          },
          "region": {
            "type": "string",
            "description": "State/province."
          },
          "country": {
            "type": "string",
            "description": "ISO country code, e.g. `AU`. Several as a comma list (`AU,NZ,SG`) match any of them."
          },
          "radius_km": {
            "type": "number",
            "description": "Optional radius around the point."
          }
        }
      },
      "SearchResponse": {
        "type": "object",
        "required": [
          "results",
          "total",
          "next_cursor"
        ],
        "properties": {
          "interpreted": {
            "type": "object",
            "description": "The compiled query that actually ran (entity, normalized filters, sort, limit). Its `resolved` section carries derived state — e.g. which employers a company name matched, or which exact industry labels your words widened from."
          },
          "interpreted_text": {
            "type": "string",
            "description": "The same interpretation as one plain sentence."
          },
          "relaxed": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Plain-English notes for anything dropped or widened because the query as asked matched nothing. Absent when it ran exactly as written."
          },
          "relaxed_events": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Machine-readable form of `relaxed`: `{code, field, from, to}` per change."
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Ranked records for this page. On `count` requests each row also carries a `match_tier`: `strict` (clearly matches the keywords), `filtered` (exact structured-filter match on a no-keyword query), or `ranked` (relevance backfill)."
          },
          "total": {
            "type": "integer",
            "description": "Matches across all pages for the structured filters. Exact on first-page keyword searches (a side count runs past the engine cap); otherwise capped per `total_is_lower_bound`."
          },
          "strong_matches": {
            "type": "integer",
            "description": "Of `total`, how many clearly match the free-text keywords. Answer 'how many …' questions with this, never with `total`, when keywords are present."
          },
          "total_is_lower_bound": {
            "type": "boolean",
            "description": "True when counting stopped at the cap — render `total` as `10,000+`."
          },
          "summary": {
            "$ref": "#/components/schemas/FulfillmentSummary",
            "description": "Present on `count` requests."
          },
          "next_cursor": {
            "type": "string",
            "description": "Pass back as `cursor` to fetch the next page; `null` when the result set is exhausted. Cursors expire on data refreshes and version upgrades; a 400 `invalid_request` means restart from page one."
          }
        }
      },
      "FulfillmentSummary": {
        "type": "object",
        "description": "Returned on `count` requests: a self-describing account of the retrieval, so callers (and their agents) can explain the result set without guessing.",
        "required": [
          "requested_count",
          "returned_count",
          "composition",
          "stopped_reason"
        ],
        "properties": {
          "requested_count": {
            "type": "integer"
          },
          "returned_count": {
            "type": "integer"
          },
          "composition": {
            "type": "object",
            "description": "Rows per match tier, e.g. `{\"strict\": 46, \"ranked\": 54}`."
          },
          "stopped_reason": {
            "type": "string",
            "enum": [
              "target_reached",
              "strict_pool_exhausted",
              "results_exhausted",
              "budget_exhausted"
            ],
            "description": "Why retrieval stopped. `strict_pool_exhausted` means the high-confidence tier ran out before the target — the honest under-fill, never padded with junk."
          },
          "quality_bar_applied": {
            "type": "string"
          },
          "strict_pool": {
            "type": "integer",
            "description": "Exact size of the high-confidence tier when a strict phase ran."
          },
          "filter_total": {
            "type": "integer",
            "description": "Size of the broad set backfill draws from."
          },
          "dedup": {
            "type": "object",
            "description": "`duplicates_removed` across retrieval, plus the method."
          },
          "quarantine": {
            "type": "object",
            "description": "Low-quality records excluded before the response (`records_excluded_as_low_quality`, `excluded_reasons` such as `garbled_name`). Never silent."
          },
          "retrieval": {
            "type": "object",
            "description": "`internal_calls_used` vs `calls_budget`."
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Anything the engine changed or could not honour, in plain English."
          }
        }
      },
      "Person": {
        "type": "object",
        "description": "A canonical person record. Company firmographics are denormalized onto the person (the `company_*` fields).",
        "properties": {
          "id": {
            "type": "string",
            "description": "Deterministic id (`psn_…`), stable per person across data refreshes."
          },
          "email": {
            "type": "string",
            "description": "Verified work email (present on a minority of records)."
          },
          "cellphone": {
            "type": "string",
            "description": "Mobile number, when known."
          },
          "waterfall": {
            "type": "object",
            "description": "Present on `/v1/enrich/person` when the waterfall ran (or was refused): per field, `delivered`, `withheld`, `not_found` or `already_held`, plus a `note` when there is something to say.",
            "properties": {
              "email": {
                "type": "string"
              },
              "mobile": {
                "type": "string"
              },
              "note": {
                "type": "string"
              }
            }
          },
          "direct_phone": {
            "type": "string",
            "description": "Direct dial, when known."
          },
          "name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "seniority": {
            "type": "string",
            "description": "Seniority band: one of `individual`, `manager`, `director`, `vp`, `executive`."
          },
          "role_started": {
            "type": "string",
            "format": "date",
            "description": "When this person started their current role, per the data source. Recency signal only: it does not confirm the person is still in the role today."
          },
          "last_observed_at": {
            "type": "string",
            "format": "date",
            "description": "When the data source last saw this person's profile on LinkedIn. The freshness signal: the older it is, the likelier the title or employer has moved on."
          },
          "email_status": {
            "type": "string",
            "description": "The data source's own per-address verdict (e.g. verified, catch_all). A catch-all domain accepts every address, so treat those as risky sends."
          },
          "email_last_verified_at": {
            "type": "string",
            "format": "date",
            "description": "When the source last verified this address. Present when the source provides it."
          },
          "about_me": {
            "type": "string",
            "description": "The person's own bio, when the source has one."
          },
          "education": {
            "type": "string",
            "description": "Education history, when known."
          },
          "job_description": {
            "type": "string",
            "description": "Their description of the current role, when known."
          },
          "certifications": {
            "type": "string",
            "description": "Professional certifications, when known."
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Languages the person lists, lowercased."
          },
          "company_about_us": {
            "type": "string",
            "description": "The employer's description, carried onto the person row for exports and outreach personalisation. Present for most employed people; blank when the source has none."
          },
          "linkedin_url": {
            "type": "string"
          },
          "company_domain": {
            "type": "string"
          },
          "company_tech": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The employer's detected tech stack (denormalized)."
          },
          "city": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "country": {
            "type": "string",
            "description": "ISO country code."
          },
          "location": {
            "type": "string",
            "description": "Composed `City, Region, Country` from the person's own city/region/country, blanks skipped. Ask for it by name in `columns`."
          },
          "job_function": {
            "type": "string",
            "description": "Department/function, e.g. `Marketing`."
          },
          "persona": {
            "type": "string"
          },
          "seniority_rank": {
            "type": "integer",
            "description": "Numeric seniority rank (higher = more senior)."
          },
          "company_industry": {
            "type": "string"
          },
          "company_naics": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "company_employees": {
            "type": "integer"
          },
          "company_entity_type": {
            "type": "string"
          },
          "company_num_locations": {
            "type": "integer"
          },
          "company_specialties": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "company_city": {
            "type": "string"
          },
          "company_region": {
            "type": "string"
          },
          "company_country": {
            "type": "string"
          },
          "company_location": {
            "type": "string",
            "description": "Composed `City, Region, Country` of the employer, from company_city/company_region/company_country."
          },
          "roles": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Role"
            },
            "description": "Employment history."
          },
          "signals": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Intent/timing tags."
          }
        }
      },
      "Role": {
        "type": "object",
        "description": "One position in a person's employment history.",
        "properties": {
          "title": {
            "type": "string"
          },
          "company": {
            "type": "string"
          },
          "current": {
            "type": "boolean"
          }
        }
      },
      "Company": {
        "type": "object",
        "description": "A canonical company record.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Deterministic id (`cmp_…`), stable per company across refreshes."
          },
          "domain": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "country": {
            "type": "string",
            "description": "ISO country code."
          },
          "location": {
            "type": "string",
            "description": "Composed `City, Region, Country` from the company's city/region/country, blanks skipped. Ask for it by name in `columns`."
          },
          "industry": {
            "type": "string"
          },
          "revenue": {
            "type": "number",
            "description": "Annual revenue (USD)."
          },
          "employees": {
            "type": "integer"
          },
          "tech": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Detected tech stack (sparse enrichment)."
          },
          "total_funding": {
            "type": "number",
            "description": "Total funding raised (USD), when known."
          },
          "last_funding_date": {
            "type": "string",
            "description": "Most recent funding date (YYYY-MM-DD)."
          },
          "last_funding_type": {
            "type": "string",
            "description": "e.g. `Series A`."
          },
          "open_roles": {
            "type": "integer",
            "description": "Tracked open-role count (hiring signal)."
          },
          "employee_growth_rate": {
            "type": "integer",
            "description": "Monthly LinkedIn headcount growth (%)."
          },
          "naics": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "NAICS codes plus their 2–5 digit prefixes."
          },
          "specialties": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "about_us": {
            "type": "string"
          },
          "num_locations": {
            "type": "integer"
          },
          "entity_type": {
            "type": "string",
            "description": "e.g. `Privately Held`, `Public Company`."
          },
          "employee_range": {
            "type": "string",
            "description": "Headcount band, e.g. `201 to 500`."
          },
          "year_founded": {
            "type": "integer"
          },
          "signals": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Intent/timing tags."
          }
        }
      },
      "EnrichFieldResult": {
        "type": "object",
        "description": "Resolved fields (first-hit-wins), returned flat, with the winning `source` and its `confidence`. The exact fields depend on the operation. A `verification` block is attached when the result contains an email or phone.",
        "properties": {
          "confidence": {
            "type": "number",
            "description": "Confidence of the winning source, 0–1."
          },
          "source": {
            "type": "string",
            "description": "The source that produced the result."
          },
          "verification": {
            "$ref": "#/components/schemas/VerificationBlock"
          }
        },
        "additionalProperties": true
      },
      "EnrichMergeResult": {
        "type": "object",
        "description": "A full person record merged (fill-all) across every source that had data.",
        "properties": {
          "fields": {
            "$ref": "#/components/schemas/Person",
            "description": "The merged record."
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Every source that contributed."
          },
          "verified": {
            "type": "boolean",
            "description": "Whether the record passed verification."
          },
          "verification": {
            "$ref": "#/components/schemas/VerificationBlock"
          }
        }
      },
      "VerificationBlock": {
        "type": "object",
        "description": "Auto-attached verification for any email/phone in the result, keyed by field.",
        "properties": {
          "email": {
            "$ref": "#/components/schemas/VerdictWithSignals"
          },
          "phone": {
            "$ref": "#/components/schemas/VerdictWithSignals"
          }
        }
      },
      "VerdictWithSignals": {
        "type": "object",
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "signals": {
            "type": "object",
            "additionalProperties": true,
            "description": "Component signals behind the verdict."
          }
        }
      },
      "BatchRequest": {
        "type": "object",
        "required": [
          "operation",
          "inputs"
        ],
        "properties": {
          "operation": {
            "type": "string",
            "description": "The enrichment to run over every input.",
            "enum": [
              "linkedin_to_email",
              "email_to_linkedin",
              "reverse_email",
              "reverse_linkedin"
            ]
          },
          "inputs": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "description": "1–100 inputs. Each carries the one field the operation reads: `email` for reverse_email and email_to_linkedin, `linkedin_url` for reverse_linkedin and linkedin_to_email.",
            "items": {
              "type": "object",
              "properties": {
                "email": {
                  "type": "string",
                  "description": "Email address, for reverse_email and email_to_linkedin."
                },
                "linkedin_url": {
                  "type": "string",
                  "description": "LinkedIn profile URL, for reverse_linkedin and linkedin_to_email."
                }
              }
            }
          }
        }
      },
      "BatchResponse": {
        "type": "object",
        "required": [
          "results"
        ],
        "properties": {
          "results": {
            "type": "array",
            "description": "One entry per input, in input order. An enrichment result object on success; `null` when nothing resolved; `{ \"error\": \"missing <field>\" }` when the input omitted the operation's field.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "VerifyResponse": {
        "type": "object",
        "required": [
          "field",
          "value",
          "valid"
        ],
        "properties": {
          "field": {
            "type": "string",
            "example": "email"
          },
          "value": {
            "type": "string",
            "example": "ada@acme.com"
          },
          "valid": {
            "type": "boolean"
          },
          "signals": {
            "type": "object",
            "additionalProperties": true,
            "description": "Component signals behind the verdict. Email: `syntax`, `domain`, `has_mx`, `disposable`, `mailbox_verified` (always false: the mailbox itself is never probed), `catch_all` (always `unknown`: catch-all status cannot be seen at this level). Phone: `type`, `region`, `e164`."
          },
          "summary": {
            "type": "string",
            "description": "Plain-language statement of what the verdict does and does not mean."
          },
          "not_checked": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What this verifier cannot see. For email that includes mailbox existence and catch-all status; `valid: true` must not be read as proof the address is real."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "description": "The single error envelope used by every endpoint.",
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable, machine-readable error code to branch on.",
                "enum": [
                  "invalid_request",
                  "unauthorized",
                  "unparseable_query",
                  "rate_limited",
                  "no_data",
                  "not_found",
                  "method_not_allowed",
                  "timeout",
                  "unavailable",
                  "internal"
                ]
              },
              "message": {
                "type": "string",
                "description": "Human-readable, client-safe message."
              },
              "retry_after": {
                "type": "integer",
                "description": "Seconds to wait before retrying; present on `rate_limited` and `unavailable`."
              }
            }
          }
        }
      }
    }
  }
}