---
title: "Sync existing customers"
method: POST
path: "/api/v1/customers"
tags: ["API Reference"]
---

# Sync existing customers

`POST /api/v1/customers`

## Request

- Base URL: `https://revnu.com`
- URL: `https://revnu.com/api/v1/customers`
- Auth: HTTP bearer

Import signups, trials and customers into Leads and exclude them from cold outreach.

Requires the `leads:write` scope.

**Response.** `{ "ok": true, "leads": 1, "stage": "customer" }`. A stale `sourceUpdatedAt` returns `ignored: true` and the retained relationship stage.

`leads` counts matched or created company records. A personal email or LinkedIn profile can return zero company records while still being excluded. Repeat the same `source` and `externalId` to update the relationship without duplicating the company. Outreach history is preserved. If several customer records match a company, a paying customer takes precedence over a trial, signup or former customer.

Known emails, company domains and LinkedIn profiles enter the enforced cold-outreach exclusions. Queued emails and open cold-outreach approval cards attached to matched leads or contacts are cancelled. Send gates recheck exclusions before sending; delivered messages cannot be recalled. Known contact profiles saved later are added to the exclusions too. An email alone cannot identify an unknown LinkedIn recipient.

Cancellation uses `former_customer` and keeps the exclusion. Omitting a customer from a later import does not unblock them. Customer-sync blocks cannot be removed through the blocklist endpoint.

A `400` identifies an invalid payload. A `401` means the token is missing or invalid; `403` means it lacks `leads:write`. Keep tokens server-side, verify signatures on your source provider's webhook handler, and retry network failures or `5xx` responses with backoff. Read the current source record and serialize updates per customer ID so a delayed event cannot overwrite newer state. Check a synced identifier through [the block list](/docs/blocklist). Confirm a real source change appears there before treating ongoing sync as connected.

## Request body

- object

## Response `200`

{ "ok": true, "leads": 1, "stage": "customer" }. A stale sourceUpdatedAt returns ignored: true and the retained relationship stage. leads counts matched or created company records. A personal email or LinkedIn profile can return zero company records while still being excluded. Repeat the same source

- union
  - object
    - `leads` number, required
    - `stage` 'customer' | 'former_customer' | 'signed_up' | 'trial', required
    - `ignored` boolean, required
    - `ok` true, required
  - object
    - `leads` number, required
    - `stage` 'customer' | 'former_customer' | 'signed_up' | 'trial', required
    - `ok` true, required

## Other responses

- `400`: The request is malformed; the error names the problem.
- `401`: Missing, malformed, unknown or revoked token.
- `402`: `setup_pending`: the account hasn't started its trial. Finish setup with `GET /setup`.
- `403`: The token lacks the scope in `requiredScope`.
- `409`: A settled refusal: `invalid_action` (see `actions`) or `rejected`.
- `429`: Rate limited.
- `503`: Temporarily unavailable; retry the same call.

---

[API](https://skmtc.dev/revnu/apis/revnu-api.md) · [All operations](https://skmtc.dev/revnu/apis/revnu-api/llms.txt) · [OpenAPI document](https://skmtc.dev/revnu/apis/revnu-api/revisions/52e523c2db61?raw)
