# Sync existing customers

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

Canonical: https://revnu.com/docs/customer-sync
Last updated: 2026-10-18

Ask your agent to connect your customer list, or call this endpoint from your backend. Import existing records first, then send future signup and billing changes to the same endpoint. A generic inbound webhook that wakes the agent does not sync customer exclusions.

```bash
curl -X POST https://revnu.com/api/v1/customers \
  -H "Authorization: Bearer $REVNU_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"source":"app","externalId":"cus_123","stage":"customer","email":"alex@example.com","website":"https://example.com","linkedinUrls":["https://www.linkedin.com/in/alex-example"]}'
```

## Body

Send one customer record per request. Required fields:

| Field | Value |
| --- | --- |
| `source` | Stable source label, 1–80 letters, digits, underscores or hyphens. |
| `externalId` | Stable record ID within that source, up to 200 characters. |
| `stage` | `signed_up`, `trial`, `customer` or `former_customer`. |

Supply at least one identifying field: `email`, `website`, `domains` or `linkedinUrls`. `domains` and `linkedinUrls` take at most 20 values each. Company domains exclude everyone at that company; personal providers such as gmail.com are rejected as company domains. An email at a personal provider excludes that address only. LinkedIn values must be personal profile URLs, not company pages.

Optional `name` and `companyName` describe the customer. Optional `signedUpAt` is a Unix timestamp in milliseconds. Supply `sourceUpdatedAt` with the source snapshot timestamp in milliseconds to prevent delayed imports or retries replacing newer relationship data. Keep using it on subsequent updates for the same source record. Text fields are limited to 320 characters, except for the source and ID limits above. Unknown fields are rejected. The API token determines the account; never include a creator ID.

## Initial import with the CLI

Export your records as a JSON object containing a `customers` array, using the same fields as the request above. Each record needs a stable source and external ID. With a `leads:write` token configured in `REVNU_API_TOKEN`:

```bash
revnu customers import --json @customers.json --dry-run
revnu customers import --json @customers.json
```

Each file can contain up to 5,000 records. The command retries transient errors and reports how many records completed before a failure. Correct the failure and rerun the same file; stable IDs make reimport safe. The dry run validates record shapes without writing. The server performs identifier validation when importing.

For one update:

```bash
revnu customers sync --json '{"source":"app","externalId":"cus_123","stage":"customer","email":"alex@example.com"}'
```

## 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.

## Frequently asked questions

### Do I have to set this up during onboarding?

No. Ask your agent when you want to connect your CRM, import a customer list or sync signups. A historical import protects the records imported so far; future changes need the ongoing connection too.

### Does cancelling a subscription make someone a prospect again?

No. Send `former_customer`. They stay excluded from cold outreach, and their outreach history remains intact.

### Will an email address also block LinkedIn messages?

Only when Revnu can match it to a saved contact with a known LinkedIn profile. Include known profile URLs in the import to exclude those people directly.
