{"openapi":"3.1.0","info":{"title":"xMap POI API","description":"Search 24M+ US Points of Interest with filters, tier-based access, and MCP support. Get your API key at https://poi-data.com","version":"1.0.0"},"paths":{"/notion/connect-session":{"post":{"tags":["notion"],"summary":"Start Notion OAuth for the calling user","operationId":"connect_session_notion_connect_session_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ConnectSessionRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/notion/finalize-connection":{"post":{"tags":["notion"],"summary":"Auto-save the user's connection after OAuth","operationId":"finalize_connection_notion_finalize_connection_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/notion/connection":{"get":{"tags":["notion"],"summary":"Is the calling user connected to Notion?","operationId":"get_connection_status_notion_connection_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/notion/disconnect":{"post":{"tags":["notion"],"summary":"Remove the user's Notion connection","operationId":"disconnect_notion_disconnect_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/notion/search":{"post":{"tags":["notion"],"summary":"Search the user's Notion workspace","operationId":"notion_search_notion_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/notion/whoami":{"get":{"tags":["notion"],"summary":"Verify the user's stored token works (calls /v1/users/me)","operationId":"user_whoami_notion_whoami_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/notion/databases":{"get":{"tags":["notion"],"summary":"List databases the integration can write to","operationId":"list_databases_notion_databases_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/notion/export-database":{"get":{"tags":["notion"],"summary":"Get the user's chosen export-target database","operationId":"get_export_database_notion_export_database_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["notion"],"summary":"Set or clear the export-target database","operationId":"set_export_database_notion_export_database_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetExportDatabaseRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/slack/connect-session":{"post":{"tags":["slack"],"summary":"Start Slack OAuth for the calling user","operationId":"connect_session_slack_connect_session_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ConnectSessionRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/slack/finalize-connection":{"post":{"tags":["slack"],"summary":"Auto-save the user's connection after OAuth","operationId":"finalize_connection_slack_finalize_connection_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/slack/connection":{"get":{"tags":["slack"],"summary":"Is the calling user connected to Slack?","operationId":"get_connection_status_slack_connection_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/slack/disconnect":{"post":{"tags":["slack"],"summary":"Remove the user's Slack connection","operationId":"disconnect_slack_disconnect_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/slack/whoami":{"get":{"tags":["slack"],"summary":"Verify the user's stored token works (calls auth.test)","operationId":"user_whoami_slack_whoami_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/slack/users":{"get":{"tags":["slack"],"summary":"List workspace users","operationId":"slack_users_slack_users_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/slack/channels":{"get":{"tags":["slack"],"summary":"List channels (filterable to bot-member only)","operationId":"slack_channels_slack_channels_get","parameters":[{"name":"member_only","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Member Only"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/slack/post-message":{"post":{"tags":["slack"],"summary":"Send a message to a Slack channel","operationId":"slack_post_message_slack_post_message_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostMessageRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/slack/export-channel":{"get":{"tags":["slack"],"summary":"Get the user's chosen export-notification channel","operationId":"get_export_channel_slack_export_channel_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["slack"],"summary":"Set or clear the export-notification channel","operationId":"set_export_channel_slack_export_channel_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetExportChannelRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sheets/connect-session":{"post":{"tags":["sheets"],"summary":"Start Google Sheets OAuth for the calling user","operationId":"connect_session_sheets_connect_session_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ConnectSessionRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sheets/finalize-connection":{"post":{"tags":["sheets"],"summary":"Auto-save the user's connection after OAuth","operationId":"finalize_connection_sheets_finalize_connection_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/sheets/connection":{"get":{"tags":["sheets"],"summary":"Is the calling user connected to Google Sheets?","operationId":"get_connection_status_sheets_connection_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/sheets/disconnect":{"post":{"tags":["sheets"],"summary":"Remove the user's Google Sheets connection","operationId":"disconnect_sheets_disconnect_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/sheets/whoami":{"get":{"tags":["sheets"],"summary":"Verify the user's stored token works (lists spreadsheets)","operationId":"user_whoami_sheets_whoami_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/sheets/spreadsheets":{"post":{"tags":["sheets"],"summary":"Create a new spreadsheet (drive.file scope)","description":"Creates a new spreadsheet in the user's Drive with a header row that\nmatches the export-summary append schema. Returns the new spreadsheet\nso the frontend can select it as the export target immediately.\n\nNote: we cannot list the user's existing spreadsheets through this\nNango provider (its proxy is locked to sheets.googleapis.com, and the\nSheets API has no list endpoint). Users either create a new one here\nor paste a spreadsheet ID directly via /sheets/export-spreadsheet.","operationId":"create_spreadsheet_sheets_spreadsheets_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSpreadsheetRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sheets/export-spreadsheet":{"get":{"tags":["sheets"],"summary":"Get the user's chosen export-target spreadsheet","operationId":"get_export_spreadsheet_sheets_export_spreadsheet_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["sheets"],"summary":"Set or clear the export-target spreadsheet","operationId":"set_export_spreadsheet_sheets_export_spreadsheet_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetExportSpreadsheetRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/drive/connect-session":{"post":{"tags":["drive"],"summary":"Start Google Drive OAuth for the calling user","operationId":"connect_session_drive_connect_session_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ConnectSessionRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/drive/finalize-connection":{"post":{"tags":["drive"],"summary":"Auto-save the user's connection after OAuth","operationId":"finalize_connection_drive_finalize_connection_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/drive/connection":{"get":{"tags":["drive"],"summary":"Is the calling user connected to Google Drive?","operationId":"get_connection_status_drive_connection_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/drive/disconnect":{"post":{"tags":["drive"],"summary":"Remove the user's Google Drive connection","operationId":"disconnect_drive_disconnect_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/drive/whoami":{"get":{"tags":["drive"],"summary":"Verify the user's stored token works","operationId":"user_whoami_drive_whoami_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/drive/ensure-folder":{"post":{"tags":["drive"],"summary":"Find-or-create the POI Exports folder","description":"Idempotent: returns the folder_id, creating the folder once if needed.\nCached on the user's Tyk meta so subsequent exports skip the search.","operationId":"ensure_folder_drive_ensure_folder_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/search":{"get":{"summary":"Search POIs (optionally enriched in one call)","description":"Search 24M+ US Points of Interest. ALWAYS display results as a table with ALL columns (name, category, city, region, postal_code, business_status, is_chain, brand_name, rating, rating_count, price_level, traffic_bucket, location). Some columns may show *** — always include them, never hide them.\n\nENRICHMENT: when the user asks for full details (phone, traffic, ratings, coordinates, opening date, parent venue, etc.), re-call this endpoint with enrich=true and the same query/filters. The response will come back fully enriched — no *** placeholders, no need to call /enrich/batch and no need to list POI IDs. Costs ~10× more credits per row, so only use enrich=true after the user explicitly says yes.\n\nSupports geo-search and filtering. Up to 250 rows per page.","operationId":"search_pois_search_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","description":"Search query text — e.g. 'starbucks', 'pizza', 'medical center'. Use '*' to match all (useful with geo or filters).","default":"*","title":"Q"},"description":"Search query text — e.g. 'starbucks', 'pizza', 'medical center'. Use '*' to match all (useful with geo or filters)."},{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Latitude for geo-search — e.g. 37.7749","title":"Lat"},"description":"Latitude for geo-search — e.g. 37.7749"},{"name":"lng","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Longitude for geo-search — e.g. -122.4194","title":"Lng"},"description":"Longitude for geo-search — e.g. -122.4194"},{"name":"radius_km","in":"query","required":false,"schema":{"type":"number","description":"Search radius in kilometers (default 5 km, max 100 km)","default":5.0,"title":"Radius Km"},"description":"Search radius in kilometers (default 5 km, max 100 km)"},{"name":"filter_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter expression. Combine with &&. Examples: 'region:Texas', 'category:Restaurant && is_chain:true', 'traffic_bucket:Very High (50K+)'","title":"Filter By"},"description":"Filter expression. Combine with &&. Examples: 'region:Texas', 'category:Restaurant && is_chain:true', 'traffic_bucket:Very High (50K+)'"},{"name":"sort_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Sort expression — e.g. 'rating:desc', 'rating_count:desc'. When using geo-search, results are sorted by distance by default.","title":"Sort By"},"description":"Sort expression — e.g. 'rating:desc', 'rating_count:desc'. When using geo-search, results are sorted by distance by default."},{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","maximum":250,"minimum":1,"description":"Results per page (1-250)","default":10,"title":"Per Page"},"description":"Results per page (1-250)"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number","default":1,"title":"Page"},"description":"Page number"},{"name":"facet_by","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated facet fields to get value counts — e.g. 'category,region,city'","title":"Facet By"},"description":"Comma-separated facet fields to get value counts — e.g. 'category,region,city'"},{"name":"max_facet_values","in":"query","required":false,"schema":{"type":"integer","maximum":250,"minimum":1,"description":"Max values returned per facet field (1-250, default 10). Bump to 51+ to get every state for `region`, or higher for full `category`/`city` lists.","default":10,"title":"Max Facet Values"},"description":"Max values returned per facet field (1-250, default 10). Bump to 51+ to get every state for `region`, or higher for full `category`/`city` lists."},{"name":"enrich","in":"query","required":false,"schema":{"type":"boolean","description":"If true, returns each row fully enriched in one call (no *** placeholders, no follow-up /enrich/batch needed). Costs ~10× more credits per row (per billing.yaml). Use after the user explicitly asks for full details.","default":false,"title":"Enrich"},"description":"If true, returns each row fully enriched in one call (no *** placeholders, no follow-up /enrich/batch needed). Costs ~10× more credits per row (per billing.yaml). Use after the user explicitly asks for full details."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enrich/{poi_id}":{"get":{"summary":"Enrich a POI — unlock all fields","description":"Returns ALL fields for a POI: name, category, city, region, brand, rating, rating_count, price_level, traffic_bucket, location, and more. This is the ONLY way to see fields that show as *** in search. Each call costs 1 enrich credit. Free tier: 100 enrich credits/month.","operationId":"enrich_poi_enrich__poi_id__get","parameters":[{"name":"poi_id","in":"path","required":true,"schema":{"type":"string","description":"The unique POI identifier from search results","title":"Poi Id"},"description":"The unique POI identifier from search results"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/enrich/batch":{"post":{"summary":"Enrich multiple POIs at once","description":"Unlock ALL fields for up to 50 POIs in one call. Each POI costs 1 enrich credit. IMPORTANT: pass the enrich_all_ids value from search results as poi_ids — no need to list IDs individually.","operationId":"enrich_batch_enrich_batch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchEnrichRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/filters":{"get":{"summary":"List available filters","description":"Returns all available filter fields and their top values with counts. Use this to populate dropdowns/autocomplete for category, region (state), city, business_status, traffic_bucket, price_level, and is_chain before searching. For query-scoped facets (e.g. cities within a search), pass `facet_by` directly to /search instead.","operationId":"list_filters_filters_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/account":{"get":{"summary":"Account & usage","description":"Shows your tier, credit usage this cycle, rate limits, and the full pricing matrix. When billing is configured, also surfaces checkout/portal URLs so the client can start an upgrade flow.","operationId":"account_info_account_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health check","description":"Check if the API is running, the search engine is reachable, and the enrichment store is mounted.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"BatchEnrichRequest":{"properties":{"poi_ids":{"type":"string","title":"Poi Ids","description":"Comma-separated POI IDs to enrich (max 50). Pass the enrich_all_ids value from search results directly."}},"type":"object","required":["poi_ids"],"title":"BatchEnrichRequest"},"ConnectSessionRequest":{"properties":{"customer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Customer"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"}},"type":"object","title":"ConnectSessionRequest"},"CreateSpreadsheetRequest":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Defaults to 'POI Exports'."}},"type":"object","title":"CreateSpreadsheetRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"PostMessageRequest":{"properties":{"channel":{"type":"string","title":"Channel","description":"Channel ID or name (e.g. #general or C123ABC)"},"text":{"type":"string","title":"Text","description":"Message text"}},"type":"object","required":["channel","text"],"title":"PostMessageRequest"},"SearchRequest":{"properties":{"query":{"type":"string","title":"Query","description":"Search text. Empty matches all pages/databases the integration can see.","default":""}},"type":"object","title":"SearchRequest"},"SetExportChannelRequest":{"properties":{"channel_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Channel Id","description":"Slack channel ID (e.g. C0123ABC). Pass null to clear."}},"type":"object","title":"SetExportChannelRequest"},"SetExportDatabaseRequest":{"properties":{"database_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Database Id","description":"Notion database ID to receive exports. Pass null to clear."}},"type":"object","title":"SetExportDatabaseRequest"},"SetExportSpreadsheetRequest":{"properties":{"spreadsheet_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Spreadsheet Id","description":"Spreadsheet ID to receive exports. Pass null to clear."}},"type":"object","title":"SetExportSpreadsheetRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}