Skip to content

Leads

The “lead” resource is table_entries — every row in a Lead Pool is a lead entry. Use these endpoints to push leads from your CRM, update lead state as your team works through the pipeline, or sync external systems.

MethodPathScope
POST/connect/table_entries/write
PATCH/connect/table_entries/:idwrite
GET/connect/tables/read
GET/connect/tables/:idread

For interactive try-it and the canonical schemas, see the reference at /docs. Everything below is concept-level — semantics, gotchas, and what the endpoint shapes look like at a glance.

  • data is free-form, customFieldData is validated. data accepts any keys (the table’s schema is inferred over time). customFieldData rejects unknown custom-field IDs with 400.
  • PATCH uses RFC 7396 merge patch. Provide null to delete a key, omit a key to leave it untouched. See Merge patch.
  • Initial leadStateId is required on create. Look it up from /connect/tables/:id (the default: true lead state is the canonical “new” state).
  • Both endpoints fire automation events. Create fires table.entry.added. Patch fires table.entry.leadState.changed, and only when the state actually changes. See Automation triggers.

A lead’s identity — names, phone numbers, emails — is stated in a contacts array, not in data. The full contract (roles, rules, matching, replace-on-PATCH) is on Contacts.

POST /connect/table_entries/
{
"tableId": "…",
"leadStateId": "…",
"data": {"course": "Kids BJJ"},
"contacts": [
{
"firstName": "Mika",
"lastName": "Toivonen",
"isPrimary": true,
"isSubject": false,
"channels": [{"kind": "phone", "value": "+4917612345678"}]
},
{"firstName": "Aino", "lastName": "Toivonen", "isSubject": true}
]
}

The parent is the primary contact and is not a subject; the child is the subject. isSubject defaults to true, so leave it off only for people the lead is actually about.

What matters most:

  • Identity in data is ignored. A lead sent without contacts has nobody on it.
  • Sending a known person again attaches them instead of creating a copy, when the name matches and every channel you send is already on file.
  • On PATCH, contacts replaces the whole set. Omit it on updates that aren’t about people.
  • Responses don’t include the people. The Connect API cannot read a lead or its contacts back; see Reading people back.

Request body:

{
contacts?: ({
firstName?: unknown | string;
middleName?: unknown | string;
lastName?: unknown | string;
fullName?: unknown | string;
contactId?: string;
channels?: ({
kind: "email" | "phone";
value: string;
isPrimary?: boolean;
consents?: ({
medium?: "whatsapp" | "sms" | "voice" | "email" | "all";
purpose: "transactional" | "marketing";
state: "granted" | "revoked";
evidence?: Record<string, Record<string, unknown>>;
})[];
})[];
isPrimary?: boolean;
// Whether the request is about this person, as opposed to them merely making it. Any number per request, at least one.
isSubject?: boolean;
// Deprecated: use `isSubject`. Accepted on writes, never returned.
isParticipant?: boolean;
})[];
// The ID of the table the entry belongs to
tableId: string;
data: Record<string, Record<string, unknown>>;
// JSON object keyed by customField ID with the corresponding value
customFieldData?: Record<string, Record<string, unknown>>;
leadStateId: string;
// Optional UUID of an appointment type the lead expressed interest in. Typically set at form submission when the form includes an `appointment-type` field (RKTL-455). Cleared to null when the referenced appointment type is deleted.
interestedInAppointmentTypeId?: string | unknown;
}

Response:

{
// The ID of the table the entry belongs to
tableId: string;
id: string;
organizationId: string;
archived: boolean;
createdAt: string /* ISO-8601 */;
updatedAt: string /* ISO-8601 */;
data: Record<string, Record<string, unknown>>;
// JSON object keyed by customField ID with the corresponding value
customFieldData?: Record<string, Record<string, unknown>>;
leadStateId: string;
firstOpenedAt: string /* ISO-8601 */ | unknown;
followUpDate: string /* ISO-8601 */ | unknown;
// Optional UUID of an appointment type the lead expressed interest in. Typically set at form submission when the form includes an `appointment-type` field (RKTL-455). Cleared to null when the referenced appointment type is deleted.
interestedInAppointmentTypeId?: string | unknown;
}

Request body (merge-patch — every field optional):

{
contacts?: ({
firstName?: unknown | string;
middleName?: unknown | string;
lastName?: unknown | string;
fullName?: unknown | string;
contactId?: string;
channels?: ({
kind: "email" | "phone";
value: string;
isPrimary?: boolean;
consents?: ({
medium?: "whatsapp" | "sms" | "voice" | "email" | "all";
purpose: "transactional" | "marketing";
state: "granted" | "revoked";
evidence?: Record<string, Record<string, unknown>>;
})[];
})[];
isPrimary?: boolean;
// Whether the request is about this person, as opposed to them merely making it. Any number per request, at least one.
isSubject?: boolean;
// Deprecated: use `isSubject`. Accepted on writes, never returned.
isParticipant?: boolean;
})[];
data?: unknown | Record<string, Record<string, unknown> | unknown>;
customFieldData?: unknown | Record<string, Record<string, unknown> | unknown>;
leadStateId?: string;
firstOpenedAt?: string /* ISO-8601 */ | unknown;
// Optional UUID of an appointment type the lead expressed interest in. Typically set at form submission when the form includes an `appointment-type` field (RKTL-455). Cleared to null when the referenced appointment type is deleted.
interestedInAppointmentTypeId?: string | unknown;
}

Response:

{
// The ID of the table the entry belongs to
tableId: string;
id: string;
organizationId: string;
archived: boolean;
createdAt: string /* ISO-8601 */;
updatedAt: string /* ISO-8601 */;
data: Record<string, Record<string, unknown>>;
// JSON object keyed by customField ID with the corresponding value
customFieldData?: Record<string, Record<string, unknown>>;
leadStateId: string;
firstOpenedAt: string /* ISO-8601 */ | unknown;
followUpDate: string /* ISO-8601 */ | unknown;
// Optional UUID of an appointment type the lead expressed interest in. Typically set at form submission when the form includes an `appointment-type` field (RKTL-455). Cleared to null when the referenced appointment type is deleted.
interestedInAppointmentTypeId?: string | unknown;
}

Fetch a Lead Pool with its lead states (you’ll need a leadStateId for create).

Record<string, unknown>