Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
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.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/lensmor:lensmor-contacts-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API 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: Lensmor Contacts API
version: 0.27.0
description: Lensmor Event Intelligence API for event discovery, exhibitor research, personnel lookup, credits, and profile matching.
license:
name: Lensmor Terms of Service
url: https://www.lensmor.com/terms
servers:
- url: https://platform.lensmor.com
security:
- bearerAuth: []
tags:
- name: Contacts
description: Search contacts and run asynchronous email or phone unlock workflows.
paths:
/external/contacts/search:
get:
tags:
- Contacts
summary: Search contacts
description: 'Search Lensmor contacts within a required company scope. Start with `company_name`, then add `role`, `person_name`, or both to narrow the results.
Use this endpoint to find people at a target account, confirm coverage before an unlock workflow, and collect personnel IDs for profile, email, phone, or outreach actions.
This is a read-only, company-scoped discovery endpoint; it does not unlock contact data. Use only the documented filters. No matches return `200 OK` with an empty `items` array. `sourceType` contains non-exclusive labels aggregated across associated events, while `linkedinActivity` and `linkedinActivityStatus` remain `null` here.'
operationId: searchContacts
parameters:
- name: company_name
in: query
required: true
description: 'Required company-name search term that scopes the contact search. Length: 1–200 characters.'
example: Acme
schema:
type: string
minLength: 1
maxLength: 200
- name: role
in: query
description: Optional job-role or title term used to narrow people within the company. Blank values are ignored.
example: VP Marketing
schema:
type: string
maxLength: 200
- name: person_name
in: query
description: Optional person-name term used to narrow people within the company. Blank values are ignored.
example: Jane
schema:
type: string
maxLength: 200
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PageSize'
responses:
'200':
description: Paginated matching contacts. A valid search with no matches returns the same envelope with an empty `items` array and zero totals.
content:
application/json:
schema:
$ref: '#/components/schemas/ContactPage'
example:
items:
- id: '101'
fullName: Jane Doe
title: VP Marketing
department: marketing
seniorityLevel: vp
linkedinUrl: https://linkedin.com/in/jane
companyName: Acme
sourceType:
- social
- visitors
email: null
phone: null
contactUnlockStatus: locked
phoneUnlockStatus: null
linkedinActivity: null
linkedinActivityStatus: null
eventCount: 3
total: 1
page: 1
pageSize: 20
totalPages: 1
hasMore: false
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/RateLimited'
/external/contacts/unlock:
post:
tags:
- Contacts
summary: Unlock contact emails
description: 'Submit personnel records for email enrichment, optionally in an event context.
Use this endpoint after contact or personnel discovery when the integration needs email addresses. Newly chargeable work consumes `15` credits per contact and returns `status: accepted` with a task identifier. `event_id` is optional; omitting it skips event membership validation. If every record is already unlocked or skipped, the endpoint can return `status: success` without a task.
Only poll the email task endpoint when `status` is `accepted` and `task_id` is present. A `201` response means the submission was processed, not that every email was found. Inspect skipped details and item-level results, and avoid duplicate work while an earlier task is active.'
operationId: unlockContactEmails
parameters:
- $ref: '#/components/parameters/CallSource'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- personnel_ids
properties:
personnel_ids:
type: array
minItems: 1
maxItems: 2000
items:
type: string
description: Lensmor personnel identifiers selected for this batch operation.
example:
- '789'
event_id:
type: string
minLength: 1
maxLength: 100
description: Optional Lensmor event identifier returned as `id` or `eventId`. When omitted, event membership validation is skipped.
example: '26855'
example:
personnel_ids:
- '789'
- '790'
event_id: '139574'
responses:
'201':
description: Unlock submission accepted, or completed with no chargeable work
content:
application/json:
schema:
$ref: '#/components/schemas/ContactUnlockSubmission'
example:
status: accepted
task_id: '321'
job_id: '321'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'429':
$ref: '#/components/responses/RateLimited'
/external/contacts/unlock-tasks/{taskId}:
get:
tags:
- Contacts
summary: Get contact unlock task
description: 'Poll an email-unlock task created by the contact email submission endpoint.
Store the returned `task_id` and use it here to make the workflow resumable across background jobs, frontend refreshes, or retries. Continue polling while `taskStatus` is `pending` or `processing`, then stop when it reaches `completed` or `failed`. Use a controlled polling interval and treat each read as a status check, not a new unlock request.
Task completion does not guarantee an email for every submitted person. Process item-level status, email, and error information independently, persist successful results, and do not retry the same task after it reaches a terminal state.'
operationId: getContactUnlockTask
parameters:
- name: taskId
in: path
required: true
schema:
type: string
pattern: ^[0-9]+$
description: Email-unlock task identifier returned as `task_id` by the submission endpoint.
example: '321'
responses:
'200':
description: Unlock task status
content:
application/json:
schema:
$ref: '#/components/schemas/ContactUnlockTask'
example:
taskId: '321'
taskStatus: processing
items:
- personnelId: '789'
status: unlocked
email: jane@acme.example
- personnelId: '790'
status: processing
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
/external/contacts/unlock-phone:
post:
tags:
- Contacts
summary: Unlock contact phone numbers
description: 'Submit personnel records for phone-number enrichment, optionally in an event context.
Use this endpoint after contact or personnel discovery when the integration needs phone numbers. Newly chargeable work consumes `150` credits per contact and returns `status: accepted` with a task identifier. `event_id` is optional; omitting it skips event membership validation. When there is no chargeable work, the endpoint can return `status: success` without a task.
Only poll the phone task endpoint when `status` is `accepted` and `task_id` is present. A `201` response does not guarantee that every phone number will be found. Inspect skipped details and item-level failures, and avoid duplicate submissions while a task is pending or processing.'
operationId: unlockContactPhones
parameters:
- $ref: '#/components/parameters/CallSource'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PhoneUnlockRequest'
example:
personnel_ids:
- '789'
event_id: '139574'
responses:
'201':
description: Phone unlock submission accepted, or completed with no chargeable work
content:
application/json:
schema:
$ref: '#/components/schemas/ContactUnlockSubmission'
example:
status: accepted
task_id: '321'
job_id: '321'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'402':
$ref: '#/components/responses/PaymentRequired'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'429':
$ref: '#/components/responses/RateLimited'
/external/contacts/unlock-phone-tasks/{taskId}:
get:
tags:
- Contacts
summary: Get phone unlock task
description: 'Poll a phone-unlock task created by the contact phone submission endpoint.
Store the returned `task_id` so the workflow can resume across background jobs, frontend refreshes, or retries. Poll while `taskStatus` is `pending` or `processing`, then stop when it reaches `completed` or `failed`. Use a controlled interval and treat each read as a status check, not a new unlock request.
Task-level completion does not guarantee a phone number for every person. Handle item-level status, phone, and `errorCode` independently, persist successful results, surface per-record failures, and do not retry a terminal task.'
operationId: getPhoneUnlockTask
parameters:
- name: taskId
in: path
required: true
schema:
type: string
pattern: ^[0-9]+$
description: Phone-unlock task identifier returned as `task_id` by the submission endpoint.
example: '321'
responses:
'200':
description: Phone unlock task status
content:
application/json:
schema:
$ref: '#/components/schemas/PhoneUnlockTask'
example:
taskId: '321'
taskStatus: completed
items:
- personnelId: '789'
status: unlocked
phone: +1 415 555 0100
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
components:
parameters:
Page:
name: page
in: query
description: One-based page number. Use `1` for the first page and increment it while `hasMore` is `true`.
example: 1
schema:
type: integer
minimum: 1
default: 1
CallSource:
name: x-call-source
in: header
required: false
schema:
type: string
enum:
- api
- agent
description: Identify the caller as `api` or `agent` for usage attribution. Defaults to `api` when omitted.
example: api
PageSize:
name: pageSize
in: query
description: Maximum number of records requested per page. The shared default is `20` and the shared upper limit is `100`; individual endpoints can document a lower maximum.
example: 20
schema:
type: integer
minimum: 1
maximum: 100
default: 20
schemas:
ContactItem:
type: object
description: Public personnel/contact record with identity, access state, and optional unlocked values.
required:
- id
- fullName
- contactUnlockStatus
properties:
id:
type: string
description: Personnel identifier to pass to profile, event, email-unlock, phone-unlock, and outreach workflows.
example: '101'
fullName:
type:
- string
- 'null'
description: Person's display name when available.
example: Jane Doe
title:
type:
- string
- 'null'
description: Current job title when available.
example: VP Marketing
department:
type:
- string
- 'null'
description: Normalized department label when available.
example: marketing
seniorityLevel:
type:
- string
- 'null'
description: Normalized seniority label when available.
example: vp
linkedinUrl:
type:
- string
- 'null'
description: LinkedIn profile URL when available.
example: https://linkedin.com/in/jane
companyName:
type:
- string
- 'null'
description: Company associated with the person when available.
example: Acme
sourceType:
type: array
description: 'Lensmor source/business labels for this person. Source labels are not mutually exclusive. Product mapping: Exhibitor is exhibitor, Social Signals is social, and Visitor is visitors. Visitor represents registered attendees obtained through organizer or data-provider partnerships; Social Signals is not proof of official registration. Event personnel lists return event-scoped labels, while personnel profile and contact search can aggregate labels across associated events.'
items:
type: string
enum:
- exhibitor
- social
- visitors
email:
type:
- string
- 'null'
description: Email address when already accessible to the caller; otherwise `null`. Search endpoints do not unlock it.
example: null
phone:
type:
- string
- 'null'
description: Phone number when already accessible to the caller; otherwise `null`. Search endpoints do not unlock it.
example: null
contactUnlockStatus:
type: string
description: Current email/contact access state for the authenticated API key owner.
example: locked
phoneUnlockStatus:
type:
- string
- 'null'
enum:
- ready
- processing
- failed
- null
description: 'Phone unlock state: `ready`, `processing`, `failed`, or `null` when no phone-unlock state is available.'
example: null
linkedinActivity:
type:
- object
- 'null'
description: LinkedIn activity summary when populated by the endpoint; otherwise `null`.
properties:
activityLevel:
type: string
description: Normalized LinkedIn activity level.
isActive:
type: boolean
description: Whether recent LinkedIn activity indicates that the person is active.
latestPostAt:
type:
- string
- 'null'
description: Timestamp of the latest known LinkedIn post when available.
linkedinActivityStatus:
type:
- string
- 'null'
description: LinkedIn activity analysis state when populated by the endpoint; otherwise `null`.
example: null
eventCount:
type:
- integer
- 'null'
description: Number of Lensmor events associated with the person when available.
example: 3
outreachMessageStatus:
type:
- string
- 'null'
description: Current outreach generation state when this endpoint includes outreach metadata.
outreachMessageChannels:
type: array
items:
type: string
description: Generated or requested outreach channels when outreach metadata is present.
ContactUnlockTask:
type: object
required:
- taskId
- taskStatus
- items
properties:
taskId:
type: string
description: Asynchronous task identifier.
pattern: ^[0-9]+$
example: '321'
taskStatus:
type: string
enum:
- pending
- processing
- completed
- failed
description: Current task lifecycle state.
items:
type: array
items:
type: object
required:
- personnelId
- status
properties:
personnelId:
type: string
description: Personnel Id returned as part of this contact unlock task object.
status:
type: string
enum:
- pending
- processing
- unlocked
- failed
description: Current normalized status for the submission, task, or generated content.
email:
type:
- string
- 'null'
description: Email address when already accessible; otherwise `null`.
errorCode:
type: string
description: Error Code returned as part of this contact unlock task object.
description: Records returned on the current page or in the current batch.
description: Asynchronous email unlock task and its item-level results.
ContactUnlockSubmission:
type: object
required:
- status
properties:
status:
type: string
enum:
- accepted
- success
description: accepted when an asynchronous task was created; success when there was no chargeable work to enqueue.
task_id:
type: string
description: TaskCenter identifier. Present when status is accepted.
pattern: ^[0-9]+$
example: '321'
job_id:
type: string
description: Alias of task_id. Present when status is accepted.
pattern: ^[0-9]+$
example: '321'
skipped_personnel_ids:
type: array
items:
type: string
description: Submitted personnel identifiers that did not create chargeable work.
skipped_detail:
type: object
properties:
invalid_personnel_ids:
type: array
items:
type: string
description: Invalid personnel ids returned as part of this contact unlock submission object.
missing_personnel_ids:
type: array
items:
type: string
description: Missing personnel ids returned as part of this contact unlock submission object.
unlinked_personnel_ids:
type: array
items:
type: string
description: Unlinked personnel ids returned as part of this contact unlock submission object.
already_unlocked_personnel_ids:
type: array
items:
type: string
description: Already unlocked personnel ids returned as part of this contact unlock submission object.
unlocking_personnel_ids:
type: array
items:
type: string
description: Unlocking personnel ids returned as part of this contact unlock submission object.
description: Reasons submitted personnel records were skipped, grouped by condition.
oneOf:
- properties:
status:
const: accepted
description: Current normalized status for the submission, task, or generated content.
required:
- task_id
- job_id
- properties:
status:
const: success
description: Current normalized status for the submission, task, or generated content.
description: Email or phone unlock submission outcome, including accepted work and skipped records.
ContactPage:
type: object
description: Standard paginated collection of contact records.
required:
- items
- total
- page
- pageSize
- totalPages
- hasMore
properties:
items:
type: array
description: Contact records returned on the current page.
items:
$ref: '#/components/schemas/ContactItem'
total:
type: integer
description: Total matching contacts across all pages.
example: 1
page:
type: integer
description: One-based page number returned.
example: 1
pageSize:
type: integer
description: Requested maximum number of contacts per page.
example: 20
totalPages:
type: integer
description: Total number of pages for the current search.
example: 1
hasMore:
type: boolean
description: Whether another page is available after the current page.
example: false
PhoneUnlockRequest:
type: object
required:
- personnel_ids
properties:
personnel_ids:
type: array
minItems: 1
maxItems: 2000
items:
type: string
description: Lensmor personnel identifiers selected for this batch operation.
example:
- '789'
event_id:
type: string
minLength: 1
maxLength: 100
description: Optional Lensmor event identifier returned as `id` or `eventId`. When omitted, event membership validation is skipped.
example: '26855'
description: Batch phone enrichment request with optional event context.
PhoneUnlockTask:
type: object
required:
- taskId
- taskStatus
- items
properties:
taskId:
type: string
description: Asynchronous task identifier.
pattern: ^[0-9]+$
example: '321'
taskStatus:
type: string
enum:
- pending
- processing
- completed
- failed
description: Current task lifecycle state.
items:
type: array
items:
type: object
required:
- personnelId
- status
properties:
personnelId:
type: string
description: Personnel Id returned as part of this phone unlock task object.
status:
type: string
enum:
- pending
- processing
- unlocked
- failed
description: Current normalized status for the submission, task, or generated content.
phone:
type:
- string
- 'null'
description: Phone number when already accessible; otherwise `null`.
errorCode:
type: string
description: Error Code returned as part of this phone unlock task object.
description: Records returned on the current page or in the current batch.
description: Asynchronous phone unlock task and its item-level results.
ApiError:
type: object
required:
- code
- message
- errorKey
- traceId
properties:
code:
type: integer
description: Numeric or symbolic code that identifies the response or business condition.
message:
type: string
description: Human-readable explanation suitable for logs or user-facing error handling.
errorKey:
type: string
description: Stable machine-readable error key for branching and analytics.
traceId:
type: string
description: Request trace identifier to include in support or incident reports.
details:
description: Optional structured business or validation context. Omitted when the error has no additional details.
description: Shared error envelope returned by public Lensmor API endpoints.
responses:
Conflict:
description: Business conflict
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
example:
code: 409
message: Request conflicts with the current resource state
errorKey: STATE_CONFLICT
traceId: 2be6d7f4-3b2d-4d11-8e2d-7a2e4c3e9a10
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
example:
code: 404
message: Resource not found
errorKey: NOT_FOUND
traceId: 2be6d7f4-3b2d-4d11-8e2d-7a2e4c3e9a10
UnprocessableEntity:
description: Selected personnel batch exceeds the runtime limit
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
example:
code: 422
message: 'Selected leads limit exceeded: requested 2001, limit 2000'
errorKey: LEAD_SELECTION_LIMIT_EXCEEDED
details:
requestedCount: 2001
limit: 2000
selectionMode: selected
traceId: 2be6d7f4-3b2d-4d11-8e2d-7a2e4c3e9a10
RateLimited:
description: Rate limit exceeded
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
example:
code: 429
message: Rate limit exceeded
errorKey: RATE_LIMIT_EXCEEDED
traceId: 2be6d7f4-3b2d-4d11-8e2d-7a2e4c3e9a10
PaymentRequired:
description: Insufficient credits
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
example:
code: 402
message: Insufficient credits
errorKey: INSUFFICIENT_CREDITS
traceId: 2be6d7f4-3b2d-4d11-8e2d-7a2e4c3e9a10
BadRequest:
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
example:
code: 400
message: Invalid request
errorKey: INVALID_REQUEST
traceId: 2be6d7f4-3b2d-4d11-8e2d-7a2e4c3e9a10
Unauthorized:
description: Missing or invalid API key
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
example:
code: 401
message: Invalid API key
errorKey: INVALID_API_KEY
traceId: 2be6d7f4-3b2d-4d11-8e2d-7a2e4c3e9a10
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: Business sk API key
description: 'Send the full Business API key from Settings -> API Keys, for example `Authorization: Bearer sk_your_api_key`.'