Yelp Lead Outcomes Webhook: Partner Integration Guide

This guide explains how to send lead status updates from your system to Yelp. When a Yelp lead progresses in your platform (for example, a job is scheduled, started, completed or closed), you send Yelp a signed HTTPS request. Yelp then keeps the lead's status in sync for the business owner.


1. Overview

MethodPOST
URLhttps://api.yelp.com/v3/integrations/{partner}/lead_updates
Content typeapplication/json
AuthenticationRequest signature (see Section 3)
Success response204 No Content

{partner} is the partner identifier Yelp assigns you during onboarding.


2. Onboarding

Before you send events, Yelp will provide you with:

  1. Your partner identifier. This is the {partner} value in the URL.
  2. A signing secret. Yelp generates it and shares it with you over a secure channel (a one-time secret link, never email or chat). If your platform generates its own webhook signing secrets, you can share yours with Yelp the same way instead. It must be at least 32 random bytes and unique to this integration. Store it securely and never send it in a request.
  3. Your signing configuration. This covers the header names and encoding, and defaults to the settings in Section 3.

Please share with Yelp:

  • The event types you plan to send, and a sample payload for each.
  • How your lead/job statuses correspond to the Yelp statuses listed in Section 4.
  • A technical contact for the integration.

If your platform already sends webhooks in a fixed format that you can't change, let us know. Yelp can often accept your existing format and map it on our side.


3. Authentication: Request Signing

Every request must be signed with HMAC-SHA256 using the secret Yelp provides. Yelp rejects any request with a missing or invalid signature.

Required headers

HeaderValue
X-TimestampCurrent Unix time in seconds, e.g. 1760875200
X-SignatureHex-encoded HMAC-SHA256 signature (lowercase)
Content-Typeapplication/json

How to compute the signature

  1. Take the exact raw request body you will send (the bytes, not a re-serialized copy).
  2. Build the string to sign: {X-Timestamp}.{raw body}. That is the timestamp, a literal ., then the body.
  3. Compute HMAC-SHA256(secret, string_to_sign).
  4. Hex-encode the result and send it in X-Signature.

Replay protection

Yelp only accepts a request if X-Timestamp is within 5 minutes of the current time. Make sure your servers' clocks are synchronized (NTP), and generate a fresh timestamp and signature for every attempt, including retries.

Secret rotation

To rotate your signing secret, contact Yelp. During the changeover Yelp accepts signatures made with either the old or the new secret, so you can switch over without failed requests. Tell Yelp when you have finished, and the old secret will be revoked. If you think your secret has been exposed, contact Yelp right away.

Example (Python)

import hashlib
import hmac
import json
import time

import requests

SECRET = b"<your signing secret>"
URL = "https://api.yelp.com/v3/integrations/<partner>/lead_updates"

body = json.dumps({
    "type": "lead.status_updated",
    "timestamp": "2026-10-19T12:00:00Z",
    "data": {
        "yelp_lead_id": "<yelp lead id>",
        "lead_status": "done",
        "external_id": "job-42",
        "event_timestamp": "2026-10-19T12:00:00Z",
    },
})

ts = str(int(time.time()))
signature = hmac.new(SECRET, f"{ts}.{body}".encode("utf-8"), hashlib.sha256).hexdigest()

resp = requests.post(
    URL,
    data=body.encode("utf-8"),  # send exactly the bytes you signed
    headers={
        "Content-Type": "application/json",
        "X-Timestamp": ts,
        "X-Signature": signature,
    },
    timeout=10,
)
resp.raise_for_status()  # expect 204

Example (shell)

BODY='{"data":{"yelp_lead_id":"<yelp lead id>","lead_status":"scheduled"}}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')

curl -X POST "https://api.yelp.com/v3/integrations/<partner>/lead_updates" \
  -H "Content-Type: application/json" \
  -H "X-Timestamp: $TS" \
  -H "X-Signature: $SIG" \
  --data "$BODY"

If your platform signs with a different scheme (for example Ed25519, base64 encoding, or a prefix such as sha256=), tell Yelp during onboarding. Yelp can usually match it.


4. Payload Format

The request body must be a JSON object. Put the lead update fields inside a data object:

{
  "type": "lead.status_updated",
  "timestamp": "2026-10-19T12:00:00Z",
  "data": {
    "yelp_lead_id": "<yelp lead id>",
    "lead_status": "done",
    "external_id": "job-42",
    "total_amount": 450.00,
    "paid_amount": 450.00,
    "event_timestamp": "2026-10-19T12:00:00Z"
  }
}

Fields in data

FieldTypeRequiredDescription
yelp_lead_idstringYesThe Yelp lead ID you received when Yelp sent you the lead. Send it back exactly as you received it.
lead_statusstringYesThe lead's new status. Must be one of the values listed under "Lead statuses" below.
external_idstringRecommendedYour own ID for the lead, job or work order.
event_timestampstringRecommendedWhen the change happened in your system, as ISO-8601 UTC (e.g. 2026-10-19T12:00:00Z).
total_amountnumberOptionalTotal value of the job.
paid_amountnumberOptionalAmount paid so far.

type and timestamp at the top level are optional and are used for traceability.

Lead statuses

lead_statusMeaning
activeThe business is engaging with the customer (contacted, quoting, etc.)
scheduledAn appointment or job has been scheduled
in_progressWork has started, or the lead has been converted into a job
doneThe job is completed
archivedThe lead is closed without a job (lost, cancelled, declined, spam)

Yelp accepts and records events with any other status value, but doesn't use them to update the lead.


5. Responses

StatusMeaningWhat to do
204 No ContentEvent accepted.Nothing; don't resend.
400 Bad RequestThe body isn't a valid JSON object.Fix the payload; don't retry it unchanged.
401 UnauthorizedThe signature is missing or invalid, or the timestamp is outside the 5-minute window.Check the secret, the string to sign, and your clock. Retry with a new timestamp and signature.
404 Not FoundUnknown {partner} identifier.Check the URL.
429 Too Many RequestsRate limit exceeded.Retry with exponential backoff.
5xxTemporary Yelp-side error.Retry with exponential backoff.

Error responses include a JSON body like this:

{
  "error": {
    "code": "INVALID_WEBHOOK_SIGNATURE",
    "description": "Webhook signature verification failed."
  }
}

Asynchronous processing

A 204 means Yelp authenticated and accepted the event. Yelp applies it to the lead shortly afterwards, so the response doesn't confirm that the lead was updated. You don't need to poll or confirm anything.


6. Delivery Guidelines

  • Retries: Retry on 429, 5xx and network timeouts, using exponential backoff (for example 1s, 2s, 4s… up to a few minutes). Re-sign every retry with a fresh timestamp.
  • Duplicates: Sending the same update more than once is safe.
  • Ordering: Send events in the order they happened where possible, and always include event_timestamp.
  • Rate limits: Keep traffic to a steady flow of real-time events. If you need to backfill historical data, contact Yelp first.
  • Timeouts: Use a client timeout of about 10 seconds. The endpoint responds quickly because processing is asynchronous.
  • Personal data: Only send the fields described above. Don't include customer names, phone numbers, addresses or other personal data unless Yelp has agreed to it.

Did this page help you?