{
  "openapi": "3.1.0",
  "info": {
    "title": "IBLead API v1",
    "version": "1.0.0",
    "description": "Core endpoints of the IBLead REST API: search Google Maps business listings, look them up, unlock or export them. Searching, counting and previewing cost 0 credits. 1 credit = 1 exported or unlocked record; records with SIRET data (France) cost 2. API access requires a credit balance above 0 or an active plan (otherwise every call returns 403). Hand-written from the API code on 2026-10-19; the full Markdown reference is https://iblead.com/llms-full.txt.",
    "contact": {
      "name": "IBLead",
      "url": "https://iblead.com/en/automation"
    },
    "termsOfService": "https://iblead.com/en/legal/terms-of-service",
    "license": {
      "name": "Proprietary, see the Terms of Service",
      "url": "https://iblead.com/en/legal/terms-of-service"
    }
  },
  "externalDocs": {
    "description": "Full API reference (Markdown)",
    "url": "https://iblead.com/llms-full.txt"
  },
  "servers": [
    {
      "url": "https://app.iblead.com/api/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Search",
      "description": "Search and count businesses (0 credits)"
    },
    {
      "name": "Lookup",
      "description": "Find businesses by IBLead ID, place ID, CID or Google Maps URL (0 credits)"
    },
    {
      "name": "Unlock and export",
      "description": "Get full records (credits)"
    },
    {
      "name": "Account",
      "description": "Balance and limits"
    }
  ],
  "paths": {
    "/businesses": {
      "get": {
        "tags": [
          "Search"
        ],
        "operationId": "listBusinesses",
        "summary": "Search and count businesses (0 credits)",
        "description": "Returns matching businesses with pagination and the total match count. Contact fields are hidden (preview) unless the record is already unlocked by your account. Use limit=1 to count.",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Macro category or subcategory name (43 languages accepted). Comma-separated for several."
          },
          {
            "name": "subcategory",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Specific subcategory. Comma-separated for several."
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO 3166-1 alpha-2 country code, e.g. FR. Comma-separated for several."
          },
          {
            "name": "countries",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated country codes (alias of a multi-value country)."
          },
          {
            "name": "cities",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated city names, e.g. Paris,Lyon."
          },
          {
            "name": "postal_codes",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated postal codes, e.g. 93100,93200."
          },
          {
            "name": "min_rating",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Minimum Google rating (0-5)."
          },
          {
            "name": "max_rating",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Maximum Google rating (0-5)."
          },
          {
            "name": "min_reviews",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Minimum review count."
          },
          {
            "name": "max_reviews",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Maximum review count."
          },
          {
            "name": "has_website",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_phone",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_email",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_facebook",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_instagram",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_linkedin",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_youtube",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_twitter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_tiktok",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_siret",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "France only: record matched to the SIRENE register."
          },
          {
            "name": "has_claimed",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Google Business Profile claimed by the owner."
          },
          {
            "name": "phone_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "mobile",
                "landline"
              ]
            },
            "description": "mobile or landline. Filtering on mobile adds 1 credit per exported record."
          },
          {
            "name": "ape_codes",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated APE/NAF codes (France only)."
          },
          {
            "name": "bbox_wkt",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 32000
            },
            "description": "WKT POLYGON (rectangle or free polygon), max 32,000 characters."
          },
          {
            "name": "include_reviews",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": true
            },
            "description": "Include Google reviews in each record."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Results per page."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Row offset (not a page number)."
          },
          {
            "name": "only_unlocked",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Only records already unlocked by this account (not expired), with full data. Returns 400 for service keys and legacy country-access plans."
          }
        ],
        "responses": {
          "200": {
            "description": "Page of businesses",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/businesses/{business_id}": {
      "get": {
        "tags": [
          "Lookup"
        ],
        "operationId": "getBusiness",
        "summary": "Get one business by IBLead ID (0 credits)",
        "description": "Contact fields are hidden until the record is unlocked (POST /unlock).",
        "parameters": [
          {
            "name": "business_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Business",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Business"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/lookup": {
      "get": {
        "tags": [
          "Lookup"
        ],
        "operationId": "lookupBusiness",
        "summary": "Look up one business by place ID, CID or Google Maps URL (0 credits)",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Feature ID (0x...:0x...), CID (numeric) or a full Google Maps URL. Short links (goo.gl) are not supported."
          }
        ],
        "responses": {
          "200": {
            "description": "Match",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Business"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/lookup/bulk": {
      "post": {
        "tags": [
          "Lookup"
        ],
        "operationId": "lookupBusinessesBulk",
        "summary": "Look up to 100 businesses at once (0 credits)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "items"
                ],
                "properties": {
                  "items": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 100,
                    "items": {
                      "type": "string"
                    },
                    "description": "Place IDs, CIDs or Google Maps URLs."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Matches",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Business"
                      }
                    },
                    "found": {
                      "type": "integer"
                    },
                    "requested": {
                      "type": "integer"
                    },
                    "errors": {
                      "type": [
                        "array",
                        "null"
                      ],
                      "items": {
                        "type": "object",
                        "properties": {
                          "input": {
                            "type": "string"
                          },
                          "error": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/unlock": {
      "post": {
        "tags": [
          "Unlock and export"
        ],
        "operationId": "unlockBusinesses",
        "summary": "Unlock records (1 credit each, 2 with SIRET data)",
        "description": "Mode 1: business_ids (max 10,000). Mode 2: count (1-10,000) plus filters, which unlocks matching records you have not unlocked yet. Already unlocked records are not charged again.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "business_ids": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "maxItems": 10000
                  },
                  "count": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000
                  },
                  "category": {
                    "type": "string"
                  },
                  "subcategory": {
                    "type": "string"
                  },
                  "country": {
                    "type": "string",
                    "description": "ISO 3166-1 alpha-2 country code, e.g. FR."
                  },
                  "min_rating": {
                    "type": "number"
                  },
                  "max_rating": {
                    "type": "number"
                  },
                  "min_reviews": {
                    "type": "integer"
                  },
                  "max_reviews": {
                    "type": "integer"
                  },
                  "has_website": {
                    "type": "boolean"
                  },
                  "has_phone": {
                    "type": "boolean"
                  },
                  "has_email": {
                    "type": "boolean"
                  },
                  "has_facebook": {
                    "type": "boolean"
                  },
                  "has_instagram": {
                    "type": "boolean"
                  },
                  "has_linkedin": {
                    "type": "boolean"
                  },
                  "has_youtube": {
                    "type": "boolean"
                  },
                  "has_twitter": {
                    "type": "boolean"
                  },
                  "has_tiktok": {
                    "type": "boolean"
                  },
                  "has_siret": {
                    "type": "boolean"
                  },
                  "has_claimed": {
                    "type": "boolean"
                  },
                  "cities": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "JSON array of city names. A plain string is rejected with 422."
                  },
                  "postal_codes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "phone_type": {
                    "type": "string",
                    "enum": [
                      "mobile",
                      "landline"
                    ]
                  },
                  "ape_codes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Unlocked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "unlocked": {
                      "type": "array",
                      "items": {
                        "type": "integer"
                      }
                    },
                    "already_unlocked": {
                      "type": "array",
                      "items": {
                        "type": "integer"
                      }
                    },
                    "cost": {
                      "type": "integer"
                    },
                    "new_balance": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/export": {
      "post": {
        "tags": [
          "Unlock and export"
        ],
        "operationId": "exportBusinesses",
        "summary": "Export full records as CSV or JSON (1 credit per new record, 2 with SIRET data)",
        "description": "Synchronous by default: returns the file (CSV) or a JSON body. Set async=true or webhook_url to get 202 with a job_id instead, then poll GET /export/jobs/{job_id}. Always set limit: without it the export takes every matching record your credit balance allows. Unknown fields are rejected with 422.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Export file. CSV body for format=csv; JSON body for format=json.",
            "headers": {
              "X-Export-Count": {
                "schema": {
                  "type": "integer"
                },
                "description": "Records exported"
              },
              "X-Daily-Remaining": {
                "schema": {
                  "type": "integer"
                },
                "description": "Daily limit remaining"
              },
              "X-Daily-Limit": {
                "schema": {
                  "type": "integer"
                },
                "description": "Daily limit"
              }
            },
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              },
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Business"
                      }
                    },
                    "count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Async job accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "const": "pending"
                    },
                    "poll_url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "job_id",
                    "status",
                    "poll_url"
                  ]
                }
              }
            },
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                },
                "description": "Job status URL"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "503": {
            "description": "Async export temporarily unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {}
                  },
                  "description": "FastAPI error body. `detail` is a string, or an object for 402 responses."
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/export/jobs/{job_id}": {
      "get": {
        "tags": [
          "Unlock and export"
        ],
        "operationId": "getExportJob",
        "summary": "Poll an async export job",
        "description": "Jobs expire 24 hours after creation. download_url is a signed link valid for 24 hours.",
        "parameters": [
          {
            "name": "job_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Job state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportJob"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/account": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccount",
        "summary": "Credit balance and export limits",
        "responses": {
          "200": {
            "description": "Account",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user_id": {
                      "type": "integer"
                    },
                    "email": {
                      "type": "string"
                    },
                    "tier": {
                      "type": "string"
                    },
                    "credits": {
                      "type": "integer"
                    },
                    "lifetime_countries": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "country_code": {
                            "type": "string"
                          },
                          "plan_type": {
                            "type": "string"
                          },
                          "activated_at": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        }
                      }
                    },
                    "daily_export_used": {
                      "type": "integer"
                    },
                    "daily_export_limit": {
                      "type": "integer"
                    },
                    "daily_export_remaining": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/countries": {
      "get": {
        "tags": [
          "Search"
        ],
        "operationId": "listCountries",
        "summary": "Countries with business counts (0 credits)",
        "description": "Accepts the same filters as GET /businesses, except country.",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Macro category or subcategory name (43 languages accepted). Comma-separated for several."
          },
          {
            "name": "subcategory",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Specific subcategory. Comma-separated for several."
          },
          {
            "name": "cities",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated city names, e.g. Paris,Lyon."
          },
          {
            "name": "postal_codes",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated postal codes, e.g. 93100,93200."
          },
          {
            "name": "min_rating",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Minimum Google rating (0-5)."
          },
          {
            "name": "max_rating",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Maximum Google rating (0-5)."
          },
          {
            "name": "min_reviews",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Minimum review count."
          },
          {
            "name": "max_reviews",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Maximum review count."
          },
          {
            "name": "has_website",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_phone",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_email",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_facebook",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_instagram",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_linkedin",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_youtube",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_twitter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_tiktok",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "has_siret",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "France only: record matched to the SIRENE register."
          },
          {
            "name": "has_claimed",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Google Business Profile claimed by the owner."
          },
          {
            "name": "phone_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "mobile",
                "landline"
              ]
            },
            "description": "mobile or landline. Filtering on mobile adds 1 credit per exported record."
          },
          {
            "name": "ape_codes",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated APE/NAF codes (France only)."
          }
        ],
        "responses": {
          "200": {
            "description": "Countries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "country_code": {
                            "type": "string"
                          },
                          "count": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/NoCredits"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key from the dashboard (API keys page): Authorization: Bearer sk_live_..."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid parameter",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "detail": {}
              },
              "description": "FastAPI error body. `detail` is a string, or an object for 402 responses."
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "detail": {}
              },
              "description": "FastAPI error body. `detail` is a string, or an object for 402 responses."
            }
          }
        }
      },
      "NoCredits": {
        "description": "API access requires credits: the account has a balance of 0 and no active plan. detail: \"API access requires credits. Buy a credit pack or a plan at https://app.iblead.com/dashboard/billing\"",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "detail": {}
              },
              "description": "FastAPI error body. `detail` is a string, or an object for 402 responses."
            }
          }
        }
      },
      "InsufficientCredits": {
        "description": "Not enough credits for this request. detail is an object: error=insufficient_credits, message, balance, and for unlocks cost and requested.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "detail": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "const": "insufficient_credits"
                    },
                    "message": {
                      "type": "string"
                    },
                    "balance": {
                      "type": "integer"
                    },
                    "cost": {
                      "type": "integer"
                    },
                    "requested": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Not found (unknown ID, expired job, or no matching records)",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "detail": {}
              },
              "description": "FastAPI error body. `detail` is a string, or an object for 402 responses."
            }
          }
        }
      },
      "ValidationError": {
        "description": "Request validation failed (wrong type, unknown body field)",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "detail": {}
              },
              "description": "FastAPI error body. `detail` is a string, or an object for 402 responses."
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit (120 requests per minute per key), too many concurrent exports (3 per user) or daily export limit reached",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "detail": {}
              },
              "description": "FastAPI error body. `detail` is a string, or an object for 402 responses."
            }
          }
        }
      }
    },
    "schemas": {
      "Business": {
        "type": "object",
        "additionalProperties": true,
        "description": "A Google Maps business. Preview records (not unlocked) only carry id, name, category, last_seen_at, is_unlocked and claimed; unlocked or exported records carry every field.",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_unlocked": {
            "type": "boolean"
          },
          "claimed": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "last_seen_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "rating": {
            "type": [
              "number",
              "null"
            ]
          },
          "review_count": {
            "type": [
              "integer",
              "null"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "country_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "website_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Google Maps URL"
          },
          "latitude": {
            "type": [
              "number",
              "null"
            ]
          },
          "longitude": {
            "type": [
              "number",
              "null"
            ]
          },
          "place_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "cid": {
            "type": [
              "string",
              "null"
            ]
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "emails": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "phones": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "socials": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "business_status": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "BusinessList": {
        "type": "object",
        "required": [
          "data",
          "total",
          "limit",
          "offset"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Business"
            }
          },
          "total": {
            "type": "integer",
            "description": "Total matching businesses"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "next_steps": {
            "description": "Optional hint for the next call"
          }
        }
      },
      "ExportRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "category": {
            "type": "string"
          },
          "subcategory": {
            "type": "string"
          },
          "country": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code, e.g. FR."
          },
          "min_rating": {
            "type": "number"
          },
          "max_rating": {
            "type": "number"
          },
          "min_reviews": {
            "type": "integer"
          },
          "max_reviews": {
            "type": "integer"
          },
          "has_website": {
            "type": "boolean"
          },
          "has_phone": {
            "type": "boolean"
          },
          "has_email": {
            "type": "boolean"
          },
          "has_facebook": {
            "type": "boolean"
          },
          "has_instagram": {
            "type": "boolean"
          },
          "has_linkedin": {
            "type": "boolean"
          },
          "has_youtube": {
            "type": "boolean"
          },
          "has_twitter": {
            "type": "boolean"
          },
          "has_tiktok": {
            "type": "boolean"
          },
          "has_siret": {
            "type": "boolean"
          },
          "has_claimed": {
            "type": "boolean"
          },
          "cities": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "JSON array of city names. A plain string is rejected with 422."
          },
          "postal_codes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "phone_type": {
            "type": "string",
            "enum": [
              "mobile",
              "landline"
            ]
          },
          "ape_codes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "bbox_wkt": {
            "type": "string",
            "maxLength": 32000
          },
          "format": {
            "type": "string",
            "enum": [
              "csv",
              "json"
            ],
            "default": "csv"
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "description": "Maximum records to export. Recommended: always set it. If omitted, the export takes all matching records up to your daily limit and credit balance."
          },
          "resume": {
            "type": "boolean",
            "default": true,
            "description": "Continue from the last export cursor"
          },
          "redownload": {
            "type": "boolean",
            "default": false,
            "description": "Re-export previously exported data"
          },
          "include_reviews": {
            "type": "boolean",
            "default": true,
            "description": "false gives much smaller files"
          },
          "only_unlocked": {
            "type": "boolean",
            "default": false,
            "description": "Re-export records you already unlocked (not expired) at 0 credits. Returns 400 for service keys and legacy country-access plans."
          },
          "async": {
            "type": "boolean",
            "default": false,
            "description": "Return 202 + job_id instead of the file"
          },
          "webhook_url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS URL. Implies async. Receives the completed job JSON, signed with X-IBLead-Signature: sha256=HMAC-SHA256(api_key, timestamp + '.' + raw_body) and X-IBLead-Timestamp."
          }
        },
        "example": {
          "category": "restaurant",
          "country": "FR",
          "cities": [
            "Paris"
          ],
          "limit": 100,
          "format": "json"
        }
      },
      "ExportJob": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "processing",
              "completed",
              "failed"
            ]
          },
          "error": {
            "type": "string",
            "description": "Set when status is failed"
          },
          "download_url": {
            "type": "string",
            "description": "Signed download link, valid 24 hours (completed jobs)"
          },
          "format": {
            "type": "string",
            "enum": [
              "csv",
              "json"
            ]
          },
          "count": {
            "type": "integer"
          },
          "credits_used": {
            "type": "integer"
          },
          "total_matching": {
            "type": "integer"
          },
          "requested": {
            "type": "integer"
          },
          "partial": {
            "type": "boolean"
          },
          "partial_reason": {
            "type": "string",
            "enum": [
              "insufficient_credits",
              "user_limit_reached",
              "daily_limit_reached"
            ]
          },
          "daily_remaining": {
            "type": "integer"
          },
          "daily_limit": {
            "type": "integer"
          },
          "created_at": {
            "type": "string"
          },
          "completed_at": {
            "type": "string"
          }
        }
      }
    }
  }
}
