- Test this endpoint in the playground
- Check out official Python client
Run a search query. This accepts a natural language query as query parameter along with additional settings. It returns a list of profiles that match the query and orders them by relevance.
The query can be:
- a simple search query like "software engineer from Ohio"
- a more complex query like "Find me engineers in California speaking at least basic english working in software industry with experience at FAANG with 2+ years of experience and at least 500 followers and at least BS degree".
- a full JD-style query that describes the ideal candidate in detail along with job description, responsibilities, requirements, etc.
If the query is already structured (for example JSON, structured text, or a boolean expression), you have two main options:
- Use the query parameter and pass the structured query as is. This is the simplest approach. Pearch.ai will interpret structured parts and priorities written in free-form text (such as “must have” or “very important”).
- Use the custom_filters parameter and map some or all structured parts to it. This gives you more control over filtering.
Use parameters to control tradeoffs between speed and quality. Here are some recipes:
- For highest quality results (30-180 seconds) use pro search with insights and profile scoring enabled:
{"query": "<YOUR QUERY HERE>", "type": "pro", "insights": true, "profile_scoring": true} - For medium to high quality results use "fast" search (<50s).
{"query": "<YOUR QUERY HERE>", "type": "fast", "insights": true, "profile_scoring": true} - For pagination, pass the previous response's
thread_idwith onlylimitand optionallyoffset. Do not resend or change search/filter parameters; including them withthread_idreturns HTTP 400.
Results are generally returned in the order of decreasing relevancy. However, you may notice results with out of order score values in some cases especially when requesting large number of results. It should be safe to use stable sorting by score field on the client side in this cases. Note that score field is only calculated and returned when profile_scoring=true.
Check out other parameters below to adjust speed vs quality and additional data that can be returned by the endpoint.
Async search callbacks
A new asynchronous search returns HTTP 202 with task_id, uuid (the same identifier), and thread_id. A cached thread result can return HTTP 200 immediately. Use async=true on /v2/search; /v2/search/submit is asynchronous by default.
Supply webhook_url, for example https://client.example.com/callback?token=<your-webhook-secret>. Use HTTPS and a dedicated secret generated and verified by your application. The supplied URL, including query parameters, is used for delivery. Callbacks have no HMAC signature or timestamp header; the URL secret does not provide cryptographic payload integrity or timestamp-based replay protection.
Each callback includes uuid, task_id (equal to uuid), thread_id, and task_status. Deduplicate by task_id, since separate tasks can share a thread. Every retry sends identical JSON bytes.
A successful callback preserves the synchronous result fields, including status="Done" and search_results, and adds task_id and task_status="completed". Polling uses the outer status="completed"; the nested result's status="Done" also means success.
Example successful callback (other search-result fields omitted):
{"uuid":"<task-uuid>","task_id":"<task-uuid>","thread_id":"<thread-uuid>","task_status":"completed","status":"Done","search_results":[]}A failed callback includes status="failed", task_status="failed", http, and a public error message. Optional code and action fields are preserved. For example:
{"uuid":"<task-uuid>","task_id":"<task-uuid>","thread_id":"<thread-uuid>","task_status":"failed","status":"failed","http":500,"error":"Internal server error"}Compatibility: older failed callbacks used status for the public error message. New failed callbacks use status="failed" and put that message in error. When accepting both formats, detect errors using http >= 400, prefer a nonempty string error for the message and fall back to status. Allow additional fields and treat newly added identifiers and task_status as optional when parsing legacy callbacks. Use a separate error model rather than the successful search-response model.
Handled cancellations use http=499 and error="Search task was cancelled before completion.". Requests rejected before a task is accepted return an HTTP error directly and do not produce a completion callback.
Delivery makes at most four attempts: one immediately, then retries after waits of 1, 2, and 4 seconds following the previous failure. Every non-2xx response or transport error triggers a retry. Each attempt uses a 10-second connection/read timeout; redirects are not followed. Return any 2xx promptly after safely accepting the event, including duplicates. Failed delivery does not rerun the search or change its completion status.
Retries run in the API worker, without a durable delivery queue. A process crash or restart can interrupt delivery, and delivery stops after the fourth failure. For newly started background tasks (HTTP 202), reconcile missing callbacks through /v2/search/status/{task_id}. For cached requests (HTTP 200), process the result in that HTTP response: polling the new task ID can return completed with result=null. If needed, reload the cached page using thread_id with the same limit and offset; this creates a separate API-call identifier.
Cost: (number of profiles returned) × (credits for type + insights + high_freshness + reveal_emails + reveal_phones).
Rate limit: 60 actual search requests per user per 60 seconds. /v2/search, /v2/search/submit, and /v2/search/count share this limit. Fully cached thread reloads that do not run a new search use a separate higher limit of 120 cached requests per user per 60 seconds. When the rate limit is exceeded, the API returns HTTP 429 with details about the triggered window, current value, and limit.
400Invalid parameter values. A request that combines thread_id with search or filter parameters is rejected with status: thread_id only supports pagination parameters for this client. Unsupported with thread_id: <field names>.
401Invalid API key
429Rate limit exceeded. JSON body contains the triggered window, current value, and limit.
