Skip to main content

Partner API Integration Guide

This guide is for third-party partners, DMS/CRM vendors, and dealer data teams who want to exchange data with CarBuddy — either by pushing customer records into CarBuddy for AI-led follow-up, or by pulling lead and conversation data out for their own systems.

If you are a dealer looking to upload a one-off file, see CSV Upload. If you want a recurring automated file feed, see SFTP. This page focuses on the programmatic REST API and how the pieces fit together.


Integration at a glance​

CarBuddy supports integration in both directions:

DirectionWhat it doesMethod
Partner → CarBuddyPush customer/vehicle records so CarBuddy runs AI-led email/SMS follow-upEnrollment REST API or SFTP / CSV feed
CarBuddy → PartnerSend you qualified leads and event notifications as they happenOutbound webhooks
Partner → CarBuddy (read)Pull your leads, conversations and outcomes into your CRM/BIPortal Data API

Choose the method that fits your systems:

  • Real-time / event-driven → Enrollment REST API (one HTTP call per batch).
  • Scheduled bulk files → SFTP feed (drop a CSV, we collect it).
  • Manual / occasional → CSV upload in the portal.

You can combine methods — for example, push records via the API and pull outcomes via the Portal Data API.


Authentication​

All programmatic access uses an API key presented in a request header. Keys are issued per client by your CarBuddy account manager — there is no public self-service signup.

SurfaceBase URLHeaderKey format
Enrollment / Campaign APIhttps://engine.carbuddyai.comX-Api-Keycb_…
Portal Data APIhttps://portal.carbuddyai.comX-API-Keycb_live_…
SFTP feedsftp.carbuddy.uk:30022SSH keyED25519 / RSA
Keep keys secret

API keys are equivalent to a password. Send them only over HTTPS, store them in a secret manager (never in source control), and rotate them if you suspect exposure. Contact your account manager to revoke or reissue a key.

Keys are scoped to a single client slug (e.g. acme-motors); presenting a key against a different slug returns 401. Each key carries its own request rate limit — 60 requests per minute by default, raisable per integration on request. Requests over the limit receive 429 Too Many Requests with a Retry-After header giving the seconds to wait.

Because a single request accepts up to 10,000 recipients, the default limit is generous for batch enrolment; it constrains per-record chatter, not volume.


1. Enrollment REST API​

The enrollment endpoint is the primary way to push customer records into a CarBuddy campaign. One call enrolls a batch of recipients; CarBuddy then runs the AI-led email/SMS sequence, handles replies, classifies leads, and hands qualified leads back to your team.

Endpoint​

POST https://engine.carbuddyai.com/webhook/{clientSlug}/enroll
HeaderValue
X-Api-KeyYour cb_… key (scoped to {clientSlug})
Content-Typeapplication/json

Request body​

FieldTypeRequiredDescription
campaign_typestring✅The campaign to enrol into, e.g. lost-sales, evhc. Your account manager confirms the value(s) available to you.
labelstring—A free-text batch label for your own tracking, e.g. "March 2026 Service Due".
recipientsarray✅1–10,000 recipient objects (see below).

Each object in recipients:

FieldTypeRequiredDescription
first_namestring✅Customer first name. If you only have a title (e.g. "Mr Patel") with no forename, put the title here rather than duplicating the surname.
last_namestring—Customer surname.
emailstring✅Customer email. Rows with a malformed email are skipped (reported back), not fatal to the batch.
mobilestring—Mobile number, ideally E.164 (+447700123456). Other formats are normalised.
vehiclestring—Vehicle description, e.g. "Volkswagen Golf 1.5 TSI".
vehicle_regstring—Registration plate. If make/model are blank, this triggers a DVLA/MOT lookup to enrich the record.
manufacturerstring—Vehicle make, e.g. "Volkswagen".
dealerstring—Dealership or selling site name.
assigned_branchstring—Branch name used for lead routing in the portal.
metadataobject—Free-form JSON object of extra attributes about the customer or enquiry (e.g. charger model, property type, survey answers). Stored on the recipient exactly as sent; unknown keys are kept, not dropped. The AI conversation only sees the metadata keys agreed for your campaign during setup (EVHC campaigns also use findings), and those agreed keys are also shown in the lead handed to the dealer team. Any other key is stored for reporting and reconciliation, not shown to the AI.
service_datestring—Date anchor for countdown-scheduled campaigns (ISO YYYY-MM-DD).
salutationstring—Title (Mr/Mrs/Ms/…).
opted_in_smsboolean—SMS marketing consent (PECR). Send false to suppress SMS for this contact. Omitting the field does not suppress SMS — see Consent & data protection.
opted_in_emailboolean—Email marketing consent. Send false to suppress email for this contact. Omitting the field does not suppress email.
Consent is an explicit false, not an omission

Both consent flags are three-state: true (consented), false (blocked — we will not send on that channel), and absent/null (unknown — we will send). If your export cannot distinguish "not consented" from "no data", filter non-consenting contacts out of the payload before you send it rather than relying on the field being omitted.

EVHC / health-check campaigns

For electronic vehicle health check (EVHC) campaigns, additional per-row fields drive routing and message content — vhc_date, sale_outcome, rag_status, work_details, and a metadata.findings[] array. Ask your account manager for the EVHC field spec if you are integrating that campaign type.

Example request​

curl -X POST https://engine.carbuddyai.com/webhook/acme-motors/enroll \
-H "X-Api-Key: cb_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"campaign_type": "lost-sales",
"label": "March 2026 Import",
"recipients": [
{
"first_name": "Sarah",
"last_name": "Jones",
"email": "sarah.jones@example.com",
"mobile": "+447700900456",
"vehicle": "Ford Kuga 1.5 EcoBoost",
"vehicle_reg": "DK21 ABC",
"manufacturer": "Ford",
"dealer": "Acme Motors",
"opted_in_sms": true,
"opted_in_email": true
}
]
}'

Responses​

StatusMeaning
201 CreatedBatch accepted — see the response body below. A 201 does not mean every row enrolled.
400 Bad RequestValidation error — the body's details array names the failing field and row index.
401 UnauthorizedMissing, invalid, expired, or wrong-client API key.
404 Not FoundUnknown client slug.
409 ConflictThe campaign has an end date that has passed. Body carries campaign_type and end_date.
422 Unprocessable EntityBatch failed a data-quality gate (e.g. the surname mapped into both name columns). Nothing was enrolled — fix the batch and resubmit.
429 Too Many RequestsRate limit exceeded; retry after the Retry-After header value.

Success body​

{
"batchId": 123,
"enrolled": 96,
"duplicates": 3,
"suppressed": 1,
"skipped": [
{ "idx": 12, "reason": "invalid_email" },
{ "idx": 40, "reason": "duplicate_email_active" },
{ "idx": 71, "reason": "suppressed" }
]
}
FieldDescription
batchIdBatch identifier — use it to find the upload in the portal.
enrolledRows that actually entered the campaign.
duplicatesRows collapsed as duplicates (already-active contacts + repeats within this batch).
suppressedRows dropped because the contact has previously opted out or bounced.
skippedPer-row drop list. idx is the zero-based index into the recipients array you sent, so you can map each entry back to your source record.
warningPresent when rows enrolled without dealer or assigned_branch — those messages render with a blank dealer name.
Always read skipped

enrolled is frequently lower than the number of recipients you sent, and that is usually correct behaviour (duplicates, opt-outs, malformed emails). Log the skipped array on your side — it is the only place the per-row reason is reported.

Common skipped reasons: invalid_email, duplicate_email_active, duplicate_email_within_batch, duplicate_branch_service_date, suppressed, lost_sales_cycle_cap.

What happens after enrollment​

CarBuddy automatically:

  • De-duplicates against customers already active in a campaign (by email or mobile).
  • Suppresses anyone who has unsubscribed or is active in a conflicting campaign.
  • Enriches records from the registration plate where make/model are missing.
  • Starts the AI-led email/SMS sequence and handles inbound replies.
  • Classifies each conversation and hands qualified leads to your team (see Outbound webhooks).

1b. Recipient events (after enrolment)​

Tell the journey that something happened to a customer after you enrolled them — a survey completed, a quote requested, a booking made. Do not re-post the customer to /enroll for this; an active recipient is deliberately skipped as a duplicate.

POST https://engine.carbuddyai.com/webhook/{your-client-slug}/recipients/events
X-Api-Key: cb_your_api_key_here
Content-Type: application/json

{
"email": "jane.doe@example.com",
"event": "survey_completed",
"occurred_at": "2026-09-04T10:15:00Z",
"metadata": { "charger_model": "myenergi Zappi 7kW" }
}
  • Identify the customer by email (case-insensitive) or mobile; add campaign_type if they are active in more than one campaign.
  • For a project-scoped campaign, also send partner_reference with the project ID supplied in enrolment metadata, and always include campaign_type. Events cannot close or hand over an unknown or ambiguous project.
  • event is snake_case, 1–64 characters. The accepted names for your campaign — and whether an event resumes the remaining journey from occurred_at — are agreed during setup.
  • metadata is merged into the customer record. Keys agreed for your campaign during setup reach the AI conversation from its next reply; any other key is stored only.
  • occurred_at is also the idempotency key: retain the same timestamp on retries. The same (customer, event, occurred_at) posted twice is a 200 with "status": "duplicate"; it does not apply the event again. A handover whose queue admission previously failed may be retried within 23 hours. An older ambiguous admission needs manual reconciliation.
  • Configured archive events stop the remaining journey. Configured handover events pause it and route the lead to the agreed contact.

Responses: 200 applied (body reports applied.metadata_merged / applied.schedule_resumed; archive and handover events also report applied.closed / applied.handover_requested) · 400 validation, campaign_type_required_for_partner_reference or campaign_type_and_partner_reference_required · 401 wrong or missing key · 404 recipient_not_found · 409 recipient_not_active, ambiguous_partner_reference or handover_admission_reconciliation_required · 422 event_not_allowed (body lists allowed), partner_reference_not_configured, partner_reference_immutable, conflicting_event_actions or handover_reason_required.

2. Checking batch and recipient status​

Once a batch is enrolled you can monitor progress in the portal under Upload History and Leads.

Programmatic read endpoints also exist under https://engine.carbuddyai.com/api/v1/{clientSlug}/… for batch summaries and recipient lookups. Programmatic read access is enabled per-partner — contact your account manager to have it turned on for your key, and they will confirm the exact endpoints and headers for your account.


3. SFTP / CSV data feed​

If you prefer to deliver scheduled files rather than call the API, use the SFTP gateway. Your DMS or data team drops CSV files onto a dedicated endpoint and CarBuddy collects and processes them automatically — no per-row API calls.

Column mapping​

The importer maps your column headers to CarBuddy fields case-insensitively and accepts common aliases, so most DMS exports work without renaming columns. Representative aliases:

CarBuddy fieldAccepted headers (any case)
first_namefirst name, firstname, forename, first
last_namelast name, lastname, surname, last
emailemail, email address, e-mail, email_address
mobilemobile, phone, tel, telephone, cell, phone number
manufacturermake, manufacturer, vehicle make
vehiclemodel, vehicle, vehicle model, car
vehicle_regreg, registration, vrm, number plate, reg number
dealerdealer, dealership, branch, location
assigned_branchbranch, assigned branch, location
salutationsalutation, title, honorific
opted_in_emailopted in email, email opt in, email consent
opted_in_smsopted in sms, sms opt in, sms consent

Files may be comma-, tab-, or pipe-delimited — the delimiter is auto-detected. Raw DMS EVHC exports with dotted headers (e.g. Contacts.RegNo, Contacts.Salute) are recognised automatically. Health-check feeds may additionally carry Sale Outcome / RAG Status (or Outcome / Urgency) columns used for EVHC routing.

If a header isn't recognised it is ignored; contact your account manager to add a mapping.


4. Outbound webhooks & lead delivery​

CarBuddy can push events to your systems as they happen — for example when a customer is classified as a qualified lead — so your CRM or DMS receives lead data without polling. Event types, payload format, and HMAC signature verification are documented on the API & Webhooks page.

DMS lead push (we integrate with your system)​

Where a partner runs a lead-management system, CarBuddy can deliver qualified leads directly into it rather than (or as well as) firing a webhook. We already integrate outbound with lead-management platforms such as Dealerweb LMS and Cooper Solutions. If you operate a DMS/CRM you'd like CarBuddy to push leads into, contact your account manager with the endpoint and authentication details and we'll scope the connector.


5. Portal Data API​

To pull your leads and conversations into your own CRM, BI, or data warehouse, use the Portal Data API.

GET https://portal.carbuddyai.com/api/leads
GET https://portal.carbuddyai.com/api/conversations
HeaderValue
X-API-KeyYour cb_live_… portal key

These endpoints return the same lead and conversation records visible in the portal — recipient details, message history, AI classifications, and conversation outcomes — filtered to your account. Ask your account manager to issue a portal API key and confirm the query parameters (date range, status filters, pagination) available for your integration.

For occasional exports without an integration, the portal also offers CSV export from the UI.


Interactive API reference​

A machine-readable OpenAPI 3 spec for the Campaign API is available to integration partners. It is not published on a public URL: ask your CarBuddy contact for a copy.

You can import the OpenAPI spec into Postman, Insomnia, or your code generator of choice.


CarBuddy sends marketing communications under UK PECR/GDPR rules. You are responsible for ensuring every contact you enrol has a lawful basis for contact — the API enrols what you send it.

How the consent flags are evaluated at send time:

Value you sendBehaviour
trueConsented — we send on that channel.
falseBlocked — we never send on that channel, for the life of the record.
Omitted / nullUnknown — we send. Treated as legacy/soft opt-in data.
Omission is not suppression

An absent opted_in_sms / opted_in_email does not stop a send. This is deliberate — recurring DMS feeds rarely carry a consent column, and their operators strip non-consenting customers at source. If your feed can express non-consent, send an explicit false; if it cannot, exclude those contacts from the payload.

Regardless of the flags:

  • Unsubscribes, STOP replies, hard bounces, and spam reports are honoured automatically and suppressed from all future campaigns for that client, not just the current one.
  • Every outbound email carries an unsubscribe link; every SMS honours STOP.
  • Contacts who complete repeated re-engagement cycles are permanently suppressed automatically.

See Data Privacy for how CarBuddy stores and processes customer data.


Getting connected​

  1. Tell your CarBuddy account manager which method you want to use (API, SFTP, or both) and which direction (push, pull, or both).
  2. For the API, we issue you a per-client cb_… key scoped to your client slug and campaign type(s).
  3. For SFTP, we provision your account and folder and register your SSH key — see SFTP Integration.
  4. Test against a small batch, confirm the records appear in the portal, then go live. For a new partner integration we can first issue a separate sandbox key, base URL and client slug on our staging environment. Nothing sent there reaches customers or dealers, and the production key follows once the sandbox run has passed.

Questions? Raise a ticket via the portal support system or contact your account manager.