Inflection.io Contacts API
The Contacts API from Inflection.io — 6 operation(s) for contacts.
The Contacts API from Inflection.io — 6 operation(s) for contacts.
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/inflectionio:inflectionio-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: Inflection Developer Contacts API
version: 1.0.0
description: 'The Inflection Developer API (`/v2`). Authenticate with a Personal Access
Token (`Authorization: Bearer inf_pat_...`).
**`/v2` is `/v1` plus more.** Every `/v1` endpoint is served here unchanged,
so a client can pin to one version and reach the whole API. On top of those
sit reads `/v1` never had: journeys, journey and email stats with a journey
rollup, and the email and list collections. `/v1` remains published.
**Response envelope.** Every response is wrapped:
`{ "data": …, "pagination": …, "errors": [...], "meta": { "status": "SUCCESS|FAILURE", "timestamp": "…" } }`.
`data` carries the payload, `pagination` appears only on paged lists, and on
failures `errors` is populated with `meta.status: "FAILURE"`.
**Query parameters are camelCase**: `pageNumber`, `pageSize`, `startTime`,
`folderId`. The journeys, emails, lists and stats reads additionally accept
the snake_case spelling of every scalar parameter (`page_number`,
`folder_id`, …); the contact, activity and list-member endpoints do not.
Repeatable parameters also accept a `[]` suffix (`status[]`, `tag[]`).
**Asynchronous contact writes.** `POST/PATCH /v2/contacts*` are processed
asynchronously: they return **200** with a `PENDING` transaction
acknowledgement (not the created/updated contact). Poll
`GET /v2/contacts/transactions/{transactionId}` for the per-contact result.
**Status-code quirks** (documented per-operation): a missing **contact** is
reported as **400** (not 404), whereas a missing **list**, **email** or
**journey** is **404**. For journeys and emails that also covers a
soft-deleted record and a malformed id. Nothing returns 201 or 204.
**Empty results are not errors.** On the paged reads, a `tag`, `folderId` or
`search` that matches nothing returns an empty page, not a 404.
**Errors.** Failures use the envelope above
(`errors[].{errorCode,message,detail}`). Authentication and authorization
failures (401/403) are returned with an empty body. The journey stats rollup
adds `RESULT_SET_TOO_LARGE` (a **400**) when a filter matches more journeys
than one request may cover; narrow it rather than paging further.
**Rate limiting.** Requests are metered per tenant. Exceeding the budget
yields **429** (empty body) on any endpoint; the `Retry-After` header gives
the seconds to wait and `X-RateLimit-Limit` the sustained per-second budget.'
servers:
- url: https://api.inflection.io
description: Production
security:
- PatAuth: []
tags:
- name: Contacts
description: Create, read, and update contacts. Writes are asynchronous.
paths:
/v2/contacts:
post:
tags:
- Contacts
operationId: createContact
summary: Create a contact
description: 'Enqueues creation of a contact. Returns a `PENDING` transaction
acknowledgement (200). The contact is created asynchronously. Any `id`
in the body is ignored.'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ContactInput'
responses:
'200':
description: Write accepted; a PENDING transaction is returned.
content:
application/json:
schema:
$ref: '#/components/schemas/TransactionResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/TooManyRequests'
/v2/contacts/batch:
post:
tags:
- Contacts
operationId: batchUpsertContacts
summary: Batch create/upsert contacts
description: 'Enqueues an upsert for up to 1000 contacts. Returns a single `PENDING`
transaction covering all items; poll the transaction for per-contact
results.'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BatchContactInput'
responses:
'200':
description: Batch accepted; a PENDING transaction is returned.
content:
application/json:
schema:
$ref: '#/components/schemas/TransactionResponse'
'400':
description: Empty list, more than 1000 items, an invalid item, or a malformed body.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/TooManyRequests'
/v2/contacts/by-email/{email}:
get:
tags:
- Contacts
operationId: getContactByEmail
summary: Get a contact by email
parameters:
- name: email
in: path
required: true
schema:
type: string
format: email
responses:
'200':
description: The contact. `data.properties` contains the full stored record.
content:
application/json:
schema:
$ref: '#/components/schemas/ContactResponse'
'400':
description: 'Returned with **400** (not 404) when no contact exists with that
email, and for a malformed request.
'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/TooManyRequests'
/v2/contacts/transactions/{transactionId}:
get:
tags:
- Contacts
operationId: getContactTransaction
summary: Get a contact write transaction
description: 'Returns the status of an async contact write. `status` is `PENDING`
while processing, `DONE` with per-contact `data.results` when complete,
or `NOT_EXIST` for an unknown id (still HTTP 200).'
parameters:
- name: transactionId
in: path
required: true
schema:
type: string
responses:
'200':
description: The transaction (PENDING, DONE, or NOT_EXIST).
content:
application/json:
schema:
$ref: '#/components/schemas/TransactionResponse'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/TooManyRequests'
/v2/contacts/{id}:
get:
tags:
- Contacts
operationId: getContact
summary: Get a contact by id
parameters:
- $ref: '#/components/parameters/ContactId'
responses:
'200':
description: The contact. `data.properties` contains the full stored record.
content:
application/json:
schema:
$ref: '#/components/schemas/ContactResponse'
'400':
description: 'Returned with **400** (not 404) when no contact exists with that id,
and for a malformed request.
'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/TooManyRequests'
patch:
tags:
- Contacts
operationId: updateContact
summary: Update a contact
description: 'Enqueues an update for the contact. Returns a `PENDING` transaction
acknowledgement (200), applied asynchronously.'
parameters:
- $ref: '#/components/parameters/ContactId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ContactInput'
responses:
'200':
description: Update accepted; a PENDING transaction is returned.
content:
application/json:
schema:
$ref: '#/components/schemas/TransactionResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/TooManyRequests'
components:
schemas:
Contact:
type: object
properties:
id:
type: string
description: Server-assigned contact id.
email:
type: string
format: email
properties:
type: object
additionalProperties: true
description: 'Arbitrary contact attributes. On reads this contains the full stored
record (including `id` and `email` alongside all other columns).
'
required:
- id
BatchContactInput:
type: object
required:
- contacts
properties:
contacts:
type: array
minItems: 1
maxItems: 1000
items:
$ref: '#/components/schemas/ContactInput'
ContactInput:
type: object
description: Body for create/update. Any `id` is ignored (the path id wins on update).
properties:
email:
type: string
format: email
description: Validated as an email when present; not strictly required.
properties:
type: object
additionalProperties: true
description: Arbitrary contact attributes to set.
Meta:
type: object
description: Envelope metadata present on every response.
properties:
status:
type: string
enum:
- SUCCESS
- FAILURE
timestamp:
type: string
format: date-time
required:
- status
ContactResponse:
type: object
properties:
data:
$ref: '#/components/schemas/Contact'
meta:
$ref: '#/components/schemas/Meta'
ErrorEnvelope:
type: object
description: Standard failure envelope.
properties:
errors:
type: array
items:
$ref: '#/components/schemas/ErrorItem'
meta:
$ref: '#/components/schemas/Meta'
ContactTransaction:
type: object
description: Acknowledgement / status of an asynchronous contact write.
properties:
transactionId:
type: string
status:
type: string
enum:
- PENDING
- DONE
- ERROR
- NOT_EXIST
description: '`NOT_EXIST` is returned (with HTTP 200) for an unknown transaction id.'
error:
type: string
data:
type: object
description: Per-contact results; populated only when `status` is `DONE`.
properties:
results:
type: array
items:
type: object
properties:
email:
type: string
status:
type: string
enum:
- CREATED
- UPDATED
- NO_CHANGE
- FAILED
error:
type: string
required:
- transactionId
- status
TransactionResponse:
type: object
properties:
data:
$ref: '#/components/schemas/ContactTransaction'
meta:
$ref: '#/components/schemas/Meta'
ErrorItem:
type: object
properties:
errorCode:
type: string
examples:
- NOT_FOUND
message:
type: string
detail:
type: string
required:
- errorCode
- message
responses:
Unauthorized:
description: Missing or invalid Personal Access Token. Empty body.
Forbidden:
description: The PAT lacks the required scope (READ for reads, WRITE for writes). Empty body.
BadRequest:
description: Malformed request or validation error.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
TooManyRequests:
description: 'Per-tenant rate limit exceeded. Empty body. Retry after the number of
seconds given in the `Retry-After` header.
'
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
X-RateLimit-Limit:
description: Sustained request budget, in requests per second, per tenant.
schema:
type: integer
parameters:
ContactId:
name: id
in: path
required: true
description: Contact id.
schema:
type: string
securitySchemes:
PatAuth:
type: http
scheme: bearer
bearerFormat: inf_pat
description: 'Personal Access Token or OAuth 2.1 access token, sent as a bearer
credential (`Authorization: Bearer inf_pat_...`). Read operations
require a token with the `READ` scope; write operations
(POST/PATCH/DELETE) require `WRITE`.
'
x-provenance:
method: harvested
publisher: Inflection.io
source: https://docs.inflection.io/api-reference/openapi.yaml
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)