JobsPipe Contacts API
Find work emails, personal emails and phone numbers for people.
Find work emails, personal emails and phone numbers for people.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/jobspipe:jobspipe-contacts-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: JobsPipe Contacts API
version: 1.0.0
description: 'JobsPipe is a unified data API over public job and technographic sources. This document covers the live public endpoints: a job-postings search that returns normalized records matching a rich filter set, and an on-demand technology-stack scanner that detects the tools a given domain runs. Authenticate with an API key issued from the JobsPipe dashboard, sent as an HTTP bearer token. Permissions are granular and read-only: the jobs:read scope grants job search, the stack:read scope grants technology-stack scans, and no scope grants write access.
Reliability for agents: write requests accept an Idempotency-Key header so retries are safe; replays return the original response with Idempotent-Replayed: true. Responses carry RFC RateLimit headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, RateLimit-Policy) describing the per-second limit, and a Retry-After header on 429 and 402. Note that the RateLimit headers describe the per-second limit only: on a 402 they may show remaining capacity while the monthly quota is exhausted, so use Retry-After, not RateLimit-Remaining, to decide when to retry a 402.
Versioning and deprecation policy: the API is versioned in the URL path (/v1). Breaking changes ship under a new version path; an endpoint is only deprecated with at least 6 months notice, signalled with Deprecation and Sunset response headers and announced in the changelog at https://jobspipe.dev/changelog.
Sandbox / test environment: a public sandbox lives under the base path /v1/sandbox (every route below it, no key required) and consumes no quota. It returns canned sample data shaped exactly like the live endpoints so agents can exercise the API safely, including a batch/bulk search and an asynchronous export that follows a 202 Accepted plus poll pattern: POST /v1/sandbox/jobs/export returns 202 with a Location header pointing at a status URL you poll with GET until the job is complete.
Error handling and retries: every error is a JSON object whose error field is a human-readable message (402 responses add message, upgrade_url and dashboard_url), never an HTML page; branch on the HTTP status, not the error text. Retry a 429 after the Retry-After header using exponential backoff; 502 and 504 are transient and safe to retry with backoff; pair any retry with an Idempotency-Key so it cannot duplicate work. Live service health is exposed at https://api.jobspipe.dev/healthz and https://api.jobspipe.dev/readiness.'
contact:
name: JobsPipe
url: https://jobspipe.dev
email: support@jobspipe.dev
servers:
- url: https://api.jobspipe.dev
security:
- apiKey: []
tags:
- name: Contacts
description: Find work emails, personal emails and phone numbers for people.
paths:
/v1/enrich/email:
post:
operationId: enrichEmail
tags:
- Contacts
summary: Find work or personal emails
x-consequence: read-only
x-side-effects: consumes credits for each contact found and not revealed before by this account; misses, cached reveals and errors cost nothing
security:
- apiKey: []
description: Finds a work or personal email for up to 100 people, each named by a LinkedIn profile URL or by full name and company domain. A found work email costs 15 credits and a personal email 10; a contact this account revealed before comes back cached and free, and a miss costs nothing. One charge covers only the found items. A personal email needs a linkedin_url to be found.
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EnrichEmailRequest'
example:
items:
- linkedin_url: https://www.linkedin.com/in/jane-doe
- full_name: Sam Lee
domain: acme.com
responses:
'200':
description: One result per item, in the order sent, and the credits charged for the batch.
content:
application/json:
schema:
$ref: '#/components/schemas/EnrichResponse'
example:
results:
- index: 0
status: enriched
type: work
value: jane.doe@northwind.com
credits: 15
- index: 1
status: not_found
type: work
value: null
credits: 0
found: 1
credits_charged: 15
'400':
description: No items, more than 100 items, an item with neither linkedin_url nor full_name and domain, or an unknown type.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Missing or invalid API key.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'402':
description: 'The balance does not cover even one contact (error: insufficient_credits).'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: 'A request with the same Idempotency-Key is still running (error: idempotency_conflict).'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: Per-second rate limit exceeded.
content:
application/json:
schema:
$ref: '#/components/schemas/RateLimitErrorResponse'
/v1/enrich/phone:
post:
operationId: enrichPhone
tags:
- Contacts
summary: Find phone numbers
x-consequence: read-only
x-side-effects: consumes credits for each contact found and not revealed before by this account; misses, cached reveals and errors cost nothing
security:
- apiKey: []
description: 'Finds a phone number for up to 100 people, each named by a LinkedIn profile URL or by full name and company domain. A found phone costs 100 credits; a phone this account revealed before comes back cached and free, and a miss costs nothing. One charge covers only the found items. A phone needs a linkedin_url to be found: name and domain items come back not_found.'
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EnrichPhoneRequest'
example:
items:
- linkedin_url: https://www.linkedin.com/in/jane-doe
responses:
'200':
description: One result per item, in the order sent, and the credits charged for the batch.
content:
application/json:
schema:
$ref: '#/components/schemas/EnrichResponse'
example:
results:
- index: 0
status: cached
type: phone
value: +1 415 555 0142
credits: 0
found: 1
credits_charged: 0
'400':
description: No items, more than 100 items, an item with neither linkedin_url nor full_name and domain, or an unknown type.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Missing or invalid API key.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'402':
description: 'The balance does not cover even one contact (error: insufficient_credits).'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: 'A request with the same Idempotency-Key is still running (error: idempotency_conflict).'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'429':
description: Per-second rate limit exceeded.
content:
application/json:
schema:
$ref: '#/components/schemas/RateLimitErrorResponse'
components:
schemas:
EnrichResponse:
type: object
required:
- results
- found
- credits_charged
properties:
results:
type: array
items:
type: object
required:
- index
- status
- type
- value
- credits
properties:
index:
type: integer
description: The item's position in the request, from 0.
status:
type: string
enum:
- enriched
- cached
- not_found
- insufficient_credits
- rate_limited
- error
description: 'enriched: found and charged now. cached: this account revealed it before, free. Every other status is free; insufficient_credits items were not looked up.'
type:
type: string
enum:
- work
- personal
- phone
value:
type: string
nullable: true
description: The email or phone, or null when none was found.
credits:
type: integer
description: Credits charged for this item.
found:
type: integer
description: Items with a value (enriched or cached).
credits_charged:
type: integer
description: Credits charged for the whole batch.
EnrichEmailRequest:
type: object
required:
- items
properties:
items:
type: array
minItems: 1
maxItems: 100
description: The people to look up. Each needs linkedin_url, or full_name and domain.
items:
type: object
properties:
linkedin_url:
type: string
description: The person's LinkedIn profile URL.
full_name:
type: string
description: The person's full name, with domain.
domain:
type: string
description: The company's website domain, e.g. acme.com, with full_name.
type:
type: string
enum:
- work
- personal
description: work (default) or personal. A personal email needs linkedin_url.
ErrorResponse:
type: object
required:
- error
properties:
error:
type: string
description: 'Human-readable error message, e.g. "Invalid search filters: unknown filter: ''query''. Did you mean query -> job_title_or?". Not a stable machine-readable code; match on the HTTP status instead. A few stack-scan errors carry a short identifier such as missing_domain or invalid_domain.'
message:
type: string
description: Additional detail. Present on 402 quota responses; other errors carry only error.
EnrichPhoneRequest:
type: object
required:
- items
properties:
items:
type: array
minItems: 1
maxItems: 100
description: The people to look up. Each needs linkedin_url, or full_name and domain; only linkedin_url items can be found.
items:
type: object
properties:
linkedin_url:
type: string
description: The person's LinkedIn profile URL.
full_name:
type: string
description: The person's full name, with domain.
domain:
type: string
description: The company's website domain, e.g. acme.com, with full_name.
RateLimitErrorResponse:
type: object
required:
- error
description: 'Sent with HTTP 429 when the per-second rate limit is exceeded. The response also carries Retry-After: 1 and the RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset and RateLimit-Policy headers. A 429 costs no credit.'
properties:
error:
type: string
description: 'Human-readable message: "Rate limit exceeded".'
parameters:
IdempotencyKey:
name: Idempotency-Key
in: header
required: false
schema:
type: string
maxLength: 255
description: 'Optional client-generated key (e.g. a UUID) that makes this POST safe to retry. A repeat with the same key returns the original response plus an Idempotent-Replayed: true header. Keys are retained for 24 hours.'
securitySchemes:
apiKey:
type: http
scheme: bearer
description: 'API key issued from the JobsPipe dashboard, prefixed jp_live_, sent as a bearer token in the Authorization header. Keys are read-only and scoped: jobs:read grants POST /v1/jobs/search, stack:read grants POST /v1/stack/scan. No scope grants write access to JobsPipe data.'
oidc:
type: openIdConnect
openIdConnectUrl: https://jobspipe.dev/.well-known/openid-configuration
description: 'OpenID Connect / OAuth 2.0 access via the JobsPipe authorization server. Supported scopes (also advertised in the protected-resource metadata at https://api.jobspipe.dev/.well-known/oauth-protected-resource): jobs:read - search normalized job postings; stack:read - run technology-stack scans.'
x-service-info:
categories:
- data
- jobs
- technographics
docs:
homepage: https://jobspipe.dev
apiReference: https://docs.jobspipe.dev
llms: https://jobspipe.dev/llms.txt