LeadMove Docs
Developers

Lead outcomes API

Report what became of a lead you received, in progress, sold or lost, with your own stage name and the sale amount, from your CRM or dialer.

Report each lead you were delivered as in progress, sold or lost with one request, straight from your CRM, dialer or enrollment system. Your provider sees it on the lead and in their figures, exactly as if you had set it in the portal. A sold report can fire the provider's conversion tracking, once.

POST https://app.leadmove.io/api/v1/leads/{leadId}/outcome

This page is written for the buyer's technical team. If you are the provider, generate the key on the buyer's page (Portal & credits → Reporting API → Generate key) and send this page along with it.

Before you send it, check that the buyer actually receives the lead reference: the Reporting API card says so for each of their webhook methods. A custom body template sends only what it contains, so it needs {lead_id} in a field the buyer stores, or a Buyer reference path on the method so the buyer's own id works here. Details in Webhook deliveries.

Authentication

Every request carries the reporting key your provider gave you as a bearer token. The key speaks for one buyer: there is no buyer in the request, and it cannot read or act on anything else.

Authorization: Bearer lm_live_…

Keep it in your system's secret store, never in a browser or a mobile app. If it leaks, ask your provider to revoke it and issue a new one; they can issue a second key before revoking the first so you switch over without a gap.

The request

{leadId} is the lead's reference, LD-XXXXXX. It is in the payload you received (leadId in the default envelope, or wherever your provider mapped it), in the X-Lead-Id header of every delivery, and on every screen and export of the portal. If your provider set up Buyer reference on your endpoint, the id your system returned when the lead was posted works too.

The body is JSON:

{
  "status": "sold",
  "label": "Enrollment",
  "amount": 1240,
  "occurredAt": "2026-09-11T14:32:00Z",
  "externalId": "DEAL-88213"
}
FieldRequiredWhat it is
statusyesin_progress, sold, lost, or null to clear a previous report.
labelnoYour own name for the stage, up to 60 characters: "Applicant", "Approved", "Enrollment". Shown to the provider next to the status.
amountnoThe value of the sale. Only with sold, 0 to 100000000. Amounts are in the buyer's currency as set in LeadMove by your provider; there is no currency field.
occurredAtnoWhen it happened on your side, ISO 8601. Defaults to now. Must not be in the future, nor more than a day before the lead was delivered.
externalIdnoYour reference for the deal, up to 120 characters.

You can report as many times as you like on one lead; the latest report is what the provider sees, and the history stays on the lead's timeline. Re-sending the same status, label and amount is harmless: the answer is changed: false and nothing is written.

Mapping your stages

You do not have to match your pipeline to three words. Map each of your stages to one of the three statuses and keep your own name in label:

Your stagestatuslabel
Applicantin_progressApplicant
Approvedin_progressApproved
EnrolledsoldEnrollment (with amount)
Declined, unreachablelostDeclined

The response

{
  "data": {
    "leadId": "LD-7K2M4A",
    "buyer": { "id": "clx8f2a10000abcdef", "name": "CCC" },
    "status": "sold",
    "label": "Enrollment",
    "amount": "1240.00",
    "currency": "CAD",
    "externalId": "DEAL-88213",
    "occurredAt": "2026-09-11T14:32:00.000Z",
    "reportedAt": "2026-09-11T14:32:04.118Z"
  },
  "changed": true
}

changed is false when the lead already carried exactly this status, label and amount. currency is the buyer's currency in LeadMove, so you can confirm the amount was understood as you meant it.

Example

curl -X POST https://app.leadmove.io/api/v1/leads/LD-7K2M4A/outcome \
  -H "Authorization: Bearer lm_live_…" \
  -H "Content-Type: application/json" \
  -d '{"status":"sold","label":"Enrollment","amount":1240}'
const res = await fetch(`https://app.leadmove.io/api/v1/leads/${leadRef}/outcome`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.LEADMOVE_REPORTING_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ status: 'in_progress', label: 'Approved' }),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);

Errors

Errors come back as JSON, never as a redirect or an HTML page. The code is the contract; messages are free to improve.

{ "error": { "code": "validation_error", "message": "…", "field": "amount" } }
HTTPcodeWhen
400validation_errorThe body is not valid JSON, or not an object
401unauthorizedNo Authorization header, wrong scheme, or a key we don't recognise
401key_revokedThe key exists but was revoked. Ask your provider for a new one
403insufficient_scopeThe key is not a buyer reporting key
403outcomes_disabledYour provider has lead statuses switched off for their account. Ask them to enable them
404lead_not_foundNo delivered lead with that reference for this buyer. A lead you were never delivered, delivered to someone else, or not delivered yet all answer this
405method_not_allowedWrong verb. The Allow header names the right one
422validation_errorA field is wrong: field names it. Typical: amount with a status other than sold, occurredAt out of range, label too long
429rate_limitedOver 120 requests a minute for this key. Retry-After says how long to wait
500internal_errorOur side. Safe to retry

Debugging: every request is logged

Every request made with a recognised key is recorded, accepted or refused: the path, the body you sent, the status and error code you got back, and how long it took. Your provider reads it on the buyer's page in LeadMove (Reporting API → Recent requests), and on each lead you reported on (View request under the reported outcome). So when a call "does not work", say when it was made: the answer is a click away on their side, without anyone reproducing the request.

Requests are kept 180 days. A request with no key, or a key that was never issued, is not attributed to anyone and leaves no record.

Common questions

Can we post the amount in our currency? No. Amounts are always in the buyer's currency as set in LeadMove; convert before sending if your system bills in another one. The response's currency tells you which it is.

We report Sold, then the deal falls through. What do we send? lost. The provider's conversion tracking, if any, is not reversed: trackers have no "un-sale". Report accurately the first time where you can.

Does a report change what we are billed? No. Nothing is billed, credited or refunded on the back of a status. To contest a lead, use a dispute.

Can we read a lead's current status back? Not in this version. The response of every report carries the state as it stands after it.

On this page