Reactive CRM Integration Guide ← Back to site

ReactiveCRM Integration Guide

Technical documentation for companies (tenants) that want to build their own integration with ReactiveCRM: ingesting leads and clients, creating deals, sending marketing events, and exporting data.

This document covers only the APIs most commonly used for external integrations. Internal reference data and admin service endpoints are intentionally out of scope.

1. Integration Overview

A typical integration flow looks like this:

text
Your system (backend / server-side proxy)
    |
    | 1. POST /api/auth/login  (obtain access + refresh tokens)
    v
ReactiveCRM
    | 2. References: GET /api/users/paged, GET /api/statuses, GET /api/stages, GET /api/lead-sources
    |    (obtain UUIDs for ownerId, authorId, statusId, etc.)
    v
    | 3. Core operations:
    |      POST /api/leads/create              — create a lead
    |      POST /api/clients/create            — create a client
    |      POST /api/contacts/create           — create a contact
    |      POST /api/deals/create              — create a deal
    |      POST /api/dashboard/marketing/events — send a marketing event
    |      POST /api/leads/import/batch         — bulk import leads
    v
    | 4. Read / export:
    |      GET /api/leads/paged                 — paged read with filters
    |      GET /api/export/leads                — NDJSON export of all leads

Key security rule: never call the CRM API directly from an end-user's browser. Keep the CRM token and internal identifiers on your backend (or a serverless function).

2. Authentication

2.1. Obtaining tokens

The authentication endpoints do not require a token:

MethodURLDescription
POST/api/auth/loginLogin with username + password, returns access + refresh tokens
POST/api/auth/refreshExchange a refresh token for a new token pair
POST/api/auth/logoutRevoke a refresh token
bash
curl -X POST "$CRM_BASE_URL/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"username": "integration", "password": "secret123"}'
json
{
  "token": "eyJhbGciOiJIUzI1NiJ9...",
  "refreshToken": "a8f3k2m9Qx7Tt1Vv...",
  "tokenType": "Bearer",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "firstName": "Integration",
    "lastName": "Bot",
    "tenantId": "660e8400-e29b-41d4-a716-446655440001"
  },
  "tenant": {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "name": "Zunga Corp"
  }
}

2.2. Token handling rules

2.3. Base settings

text
CRM_BASE_URL=https://crm.example.com

All examples below assume the headers:

http
Authorization: Bearer <CRM_ACCESS_TOKEN>
Content-Type: application/json

3. Paged API Conventions

All list endpoints of the form GET /api/*/paged share the same conventions:

ParameterTypeDefaultDescription
pageinteger0Page number, zero-based
sizeintegerper endpointPage size
sortstringcreatedAt,descSorting in field,direction format. Direction: asc or desc

Paged response shape

json
{
  "content": [ { "..." } ],
  "page": 0,
  "size": 20,
  "totalElements": 137,
  "totalPages": 7
}

Date filtering

Use fieldFrom / fieldTo params for ranges (ISO 8601):

text
createdAtFrom=2026-01-01T00:00:00Z
createdAtTo=2026-01-31T23:59:59Z

Sorting

Always ?sort=field,direction:

text
?sort=createdAt,desc
?sort=name,asc

Some filter fields have dedicated range params (e.g., dealAmountFrom/dealAmountTo).

Filtering semantics

4. References (obtaining UUIDs)

Before creating entities, obtain the UUIDs of related reference data. The main ones:

4.1. Users (GET /api/users/paged)

Used for ownerId, authorId, developingManagerIds.

bash
curl "$CRM_BASE_URL/api/users/paged?page=0&size=50&sort=createdAt,asc" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

Example response (content fragment):

json
[
  {
    "id": "7a786a66-3617-48c1-921d-97f4aaefcd35",
    "firstName": "Roman",
    "lastName": "Posledovskiy",
    "username": "roman",
    "email": "roman@example.com",
    "tenantId": "660e8400-e29b-41d4-a716-446655440001"
  }
]

4.2. Statuses (GET /api/statuses)

Used for statusId of leads, deals, and deal-party clients. Returns an array:

bash
curl "$CRM_BASE_URL/api/statuses" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"
json
[
  {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "New",
    "entityType": "LEAD"
  },
  {
    "id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
    "name": "In progress",
    "entityType": "STAGE"
  }
]

4.3. Stages (GET /api/stages)

Used for the stageId of a deal:

bash
curl "$CRM_BASE_URL/api/stages" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

4.4. Lead sources (GET /api/lead-sources)

Returns a tree of lead sources. Used for a lead's leadSourceId:

bash
curl "$CRM_BASE_URL/api/lead-sources" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"
json
[
  {
    "id": "cccc0001-0000-0000-0000-000000000001",
    "name": "Website",
    "children": [
      {
        "id": "cccc0001-0000-0000-0000-000000000002",
        "name": "Feedback form",
        "children": []
      }
    ]
  }
]

5. Leads

5.1. Create a lead (POST /api/leads/create)

bash
curl -X POST "$CRM_BASE_URL/api/leads/create" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Website inquiry: consultation",
    "ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
    "authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
    "leadSourceId": "cccc0001-0000-0000-0000-000000000002",
    "statusId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "quality": "WARM"
  }'

Request fields:

FieldTypeRequiredDescription
messagestringnoMessage / inquiry text
ownerIduuidyesResponsible user
authorIduuidyesUser who created the lead
clientIduuidnoRelated client
contactIduuidnoRelated contact
leadSourceIduuidnoLead source tree node
statusIduuidnoStatus
qualityenumnoHOT, WARM, COOL, COLD

Example 201 Created response:

json
{
  "id": "22222222-2222-2222-2222-222222222222",
  "message": "Website inquiry: consultation",
  "status": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "New"
  },
  "quality": "WARM",
  "dealId": null,
  "createdAt": "2026-09-05T20:00:00Z",
  "updatedAt": "2026-09-05T20:00:00Z",
  "version": 0,
  "author": {
    "id": "7a786a66-3617-48c1-921d-97f4aaefcd35",
    "firstName": "Roman",
    "lastName": "Posledovskiy"
  },
  "owner": {
    "id": "7a786a66-3617-48c1-921d-97f4aaefcd35",
    "firstName": "Roman",
    "lastName": "Posledovskiy"
  }
}

Keep the returned id — it is needed for the marketing event leadId (see section 8).

5.2. Paged read (GET /api/leads/paged)

bash
curl "$CRM_BASE_URL/api/leads/paged?page=0&size=20&createdAtFrom=2026-09-01T00:00:00Z&sort=createdAt,desc" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

Key filters:

ParameterTypeModeDescription
statusIduuidexactFilter by status
leadSourceIduuidexactFilter by lead source
qualityenumexactHOT, WARM, COOL, COLD
messagestringILIKESubstring in message
searchstringILIKE (OR)Search across message, contact, email, phone
contactEmailstringILIKEBy contact email
contactPhonestringILIKEBy contact phone
companystringILIKEBy company name
clientIduuidexactBy client ID
createdAtFrom / createdAtTodate-timerangeBy creation date
updatedAtFrom / updatedAtTodate-timerangeBy update date
createdByuuidexactBy lead author

There are also filters for the related deal: dealStatusId, dealStageId, dealAmountFrom/dealAmountTo, dealProbabilityFrom/dealProbabilityTo.

Sorting: createdAt, updatedAt, message, quality, status/source, and others (field,direction format).

5.3. Get a single lead (GET /api/leads/{id})

bash
curl "$CRM_BASE_URL/api/leads/$LEAD_ID" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

5.4. Bulk lead import (POST /api/leads/import/batch)

For bulk ingestion of a large number of leads, use the batch endpoint. It accepts an array of leads, creates an import-history record, and allows rolling back the whole import.

bash
curl -X POST "$CRM_BASE_URL/api/leads/import/batch" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "fileName": "leads-2026-09-05.csv",
    "leads": [
      {
        "message": "Inquiry #1",
        "ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
        "authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
        "quality": "WARM"
      },
      {
        "message": "Inquiry #2",
        "ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
        "authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
        "quality": "COOL"
      }
    ]
  }'

Example response:

json
{
  "importId": "44444444-4444-4444-4444-444444444444",
  "imported": 2,
  "total": 2,
  "skipped": []
}

History and rollback:

bash
# Import history
curl "$CRM_BASE_URL/api/leads/import/history" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

# Rollback an import
curl -X POST "$CRM_BASE_URL/api/leads/import/rollback/$IMPORT_ID" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

5.5. Quick website lead (POST /api/site/leads)

For website forms there is a single combined endpoint that atomically creates the contact, its primary phone and email, the lead, the contact–lead link, and the marketing event in one request — with idempotency via externalId.

See the dedicated guide: site-lead-multi-contract.md.

6. Clients and Contacts

6.1. Create a client (POST /api/clients/create)

bash
curl -X POST "$CRM_BASE_URL/api/clients/create" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "COMPANY",
    "name": "Romashka LLC",
    "taxId": "7700000001",
    "regNumber": "1234567890",
    "country": "RU",
    "phone": "+7-495-000-00-01",
    "email": "info@romashka.ru",
    "website": "https://romashka.ru",
    "ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
    "authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35"
  }'

Key fields:

FieldTypeApplies toDescription
typeenumallINDIVIDUAL or COMPANY (required)
namestringallDisplay name (required)
firstName / lastNamestringINDIVIDUALFirst/last name
taxIdstringCOMPANYTax ID (INN)
regNumberstringCOMPANYRegistration number
legalAddressstringCOMPANYLegal address
phone / email / websitestringallContacts
countrystringallISO country code
ownerIduuidallResponsible user
authorIduuidallAuthor
developingManagerIdsuuid[]allDeveloping managers

6.2. Paged client read (GET /api/clients/paged)

bash
curl "$CRM_BASE_URL/api/clients/paged?page=0&size=20&type=COMPANY&search=Romashka&sort=name,asc" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

Key filters: name, type (INDIVIDUAL/COMPANY), country, taxId, email, phone, lastName (individuals), search (by name/taxId/phone), createdAtFrom/createdAtTo, createdBy, developingManagerId.

6.3. Duplicate check (GET /api/clients/duplicates)

Before creating a client, check whether a similar one already exists:

bash
# By tax ID and name
curl "$CRM_BASE_URL/api/clients/duplicates?type=COMPANY&taxId=7700000001&name=Romashka" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

6.4. Create a contact (POST /api/contacts/create)

bash
curl -X POST "$CRM_BASE_URL/api/contacts/create" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Ivan",
    "lastName": "Petrov",
    "dateOfBirth": "1990-05-15",
    "gender": "MALE",
    "countryCode": "RU",
    "ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
    "authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35"
  }'

Fields: firstName (required), lastName, patronymicName, dateOfBirth (date), gender (MALE/FEMALE), countryCode, ownerId, authorId.

6.5. Paged contact read (GET /api/contacts/paged)

bash
curl "$CRM_BASE_URL/api/contacts/paged?page=0&size=20&search=Petrov&sort=createdAt,desc" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

7. Deals

7.1. Create a deal (POST /api/deals/create)

bash
curl -X POST "$CRM_BASE_URL/api/deals/create" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Server hardware delivery",
    "clientId": "9f128931-69fd-493a-9a08-be5be0e6603d",
    "statusId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
    "stageId": "dddd0001-0000-0000-0000-000000000001",
    "probability": 60,
    "amount": 150000.00,
    "ownerId": "7a786a66-3617-48c1-921d-97f4aaefcd35",
    "authorId": "7a786a66-3617-48c1-921d-97f4aaefcd35"
  }'

Key fields:

FieldTypeRequiredDescription
namestringyesDeal name
clientIduuidyesClient ID
statusIduuidnoStatus (stage status)
stageIduuidnoSales stage
probabilityintegernoProbability 0-100
amountnumbernoAmount
plannedAmountnumbernoPlanned amount
discountPercentintegernoDiscount 0-100
startDate / expectedCloseDatedate-timenoDates
ownerIduuidnoOwner
leadIduuidnoRelated lead
contactIduuidnoRelated contact
productIdsuuid[]noProducts (simplified format)
dealProductsarraynoDeal line items (full format)
dealPartiesarraynoDeal parties

7.2. Paged deal read (GET /api/deals/paged)

bash
curl "$CRM_BASE_URL/api/deals/paged?page=0&size=20&stageKind=OPEN&sort=createdAt,desc" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

Key filters: name (ILIKE), clientId, clientName, statusId, stageId, stageKind (OPEN/WON/LOST), ownerId, search, startDateFrom/startDateTo, expectedCloseDateFrom/expectedCloseDateTo, actualCloseDateFrom/actualCloseDateTo, createdAtFrom/createdAtTo.

8. Marketing Events (Attribution)

To send UTM tags, ad identifiers, and traffic sources, use:

POST /api/dashboard/marketing/events

bash
curl -X POST "$CRM_BASE_URL/api/dashboard/marketing/events" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "eventType": "lead_submitted",
    "occurredAt": "2026-09-05T20:00:00Z",
    "visitorId": "visitor-8b7f",
    "sessionId": "session-31ac",
    "leadId": "22222222-2222-2222-2222-222222222222",
    "externalId": "site-form-submit-20260905-000123",
    "source": "website",
    "channel": "paid",
    "utmSource": "google",
    "utmMedium": "cpc",
    "utmCampaign": "summer-consulting",
    "utmContent": "banner-a",
    "utmTerm": "crm consultation",
    "gclid": "EAIaIQobChMI-example",
    "landingUrl": "https://www.example.com/consultation",
    "referrer": "https://www.google.com/",
    "metadata": {
      "formName": "consultation",
      "pageType": "landing"
    }
  }'

Example response:

json
{
  "accepted": true,
  "duplicate": false,
  "eventId": "33333333-3333-3333-3333-333333333333"
}

Rules:

For details, see site-leads-integration-guide.md.

9. Data Export (NDJSON)

Export endpoints return all records of the tenant in NDJSON format (one JSON object per line, \n-separated).

EndpointDescription
GET /api/export/leadsAll tenant leads
GET /api/export/clientsAll tenant clients
GET /api/export/contactsAll tenant contacts
bash
curl "$CRM_BASE_URL/api/export/leads" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

Example response (line stream):

text
{"id":"550e8400-e29b-41d4-a716-446655440001","message":"Website inquiry","quality":"WARM","statusName":"New","createdAt":"2026-08-20T10:00:00+03:00","ownerName":"Ivan Ivanov","clientName":"Romashka LLC","contactFirstName":"Petr","contactLastName":"Petrov","leadSourceName":"Paid search"}
{"id":"550e8400-e29b-41d4-a716-446655440002","message":"Phone call","quality":"COOL","statusName":"In progress","createdAt":"2026-08-19T09:00:00+03:00","ownerName":"Maria Smirnova","clientName":null}

Important: NDJSON is not a valid JSON array. Read the response line by line via ReadableStream (do not call JSON.parse() on the whole response).

10. End-to-End Integration Example

The following scenario creates a website lead, links a contact and a client, creates a deal, and sends a marketing event.

bash
CRM_BASE_URL=https://crm.example.com
CRM_TOKEN="<access-token>"

# 1. Login
curl -s -X POST "$CRM_BASE_URL/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"username": "integration", "password": "secret123"}' | tee /tmp/login.json

CRM_TOKEN=$(jq -r '.token' /tmp/login.json)

OWNER_ID=$(curl -s "$CRM_BASE_URL/api/users/paged?page=0&size=50" \
  -H "Authorization: Bearer $CRM_TOKEN" | jq -r '.content[0].id')

# 2. Create a client
curl -s -X POST "$CRM_BASE_URL/api/clients/create" \
  -H "Authorization: Bearer $CRM_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"type\": \"COMPANY\",
    \"name\": \"Romashka LLC\",
    \"taxId\": \"7700000001\",
    \"country\": \"RU\",
    \"ownerId\": \"$OWNER_ID\",
    \"authorId\": \"$OWNER_ID\"
  }" | tee /tmp/client.json

CLIENT_ID=$(jq -r '.id' /tmp/client.json)

# 3. Create a contact
curl -s -X POST "$CRM_BASE_URL/api/contacts/create" \
  -H "Authorization: Bearer $CRM_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"firstName\": \"Ivan\",
    \"lastName\": \"Petrov\",
    \"countryCode\": \"RU\",
    \"ownerId\": \"$OWNER_ID\",
    \"authorId\": \"$OWNER_ID\"
  }" | tee /tmp/contact.json

CONTACT_ID=$(jq -r '.id' /tmp/contact.json)

# 4. Create a lead
curl -s -X POST "$CRM_BASE_URL/api/leads/create" \
  -H "Authorization: Bearer $CRM_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"message\": \"Website inquiry\",
    \"clientId\": \"$CLIENT_ID\",
    \"contactId\": \"$CONTACT_ID\",
    \"ownerId\": \"$OWNER_ID\",
    \"authorId\": \"$OWNER_ID\",
    \"quality\": \"WARM\"
  }" | tee /tmp/lead.json

LEAD_ID=$(jq -r '.id' /tmp/lead.json)

# 5. Create a deal linked to the lead
curl -s -X POST "$CRM_BASE_URL/api/deals/create" \
  -H "Authorization: Bearer $CRM_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"name\": \"Consultation for Ivan Petrov\",
    \"clientId\": \"$CLIENT_ID\",
    \"leadId\": \"$LEAD_ID\",
    \"contactId\": \"$CONTACT_ID\",
    \"amount\": 50000.00,
    \"ownerId\": \"$OWNER_ID\",
    \"authorId\": \"$OWNER_ID\"
  }"

# 6. Send a marketing event
curl -s -X POST "$CRM_BASE_URL/api/dashboard/marketing/events" \
  -H "Authorization: Bearer $CRM_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"eventType\": \"lead_submitted\",
    \"occurredAt\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
    \"leadId\": \"$LEAD_ID\",
    \"externalId\": \"request-$(uuidgen)\",
    \"source\": \"website\",
    \"channel\": \"direct\",
    \"landingUrl\": \"https://www.example.com/form\",
    \"metadata\": {\"formName\": \"consultation\"}
  }"

11. Idempotency and Error Handling

12. Quick Start

  1. Authenticate via POST /api/auth/login; store token and refreshToken.
  2. Add Authorization: Bearer <token> to every request. On 401, refresh via /api/auth/refresh.
  3. Fetch references (users/statuses/stages/lead-sources) once and cache the UUIDs.
  4. Create entities in a logical order: client → contact → lead → deal.
  5. Use paged endpoints for reads with server-side filtering and sorting.
  6. For exports, use NDJSON endpoints and read the stream line by line.
  7. For bulk ingestion, use batch endpoints (/api/leads/import/batch, /api/clients/import/batch) with rollback support.
  8. Send marketing attribution via POST /api/dashboard/marketing/events with a stable externalId.
  9. Never store or pass PII in marketing-event metadata.
  10. See detailed per-API docs: site-leads-integration-guide.md.