← Streamsynq
Webhooks

Push leads to Streamsynq from any system.

If your CRM, lead source, or custom Zapier flow can fire HTTP, you can push leads to Streamsynq. The AI acts on a valid payload within about a minute during 8am–8pm calling hours; after-hours leads are queued for 8am.

Endpoint

POST https://streamsynq.io/api/webhooks/lead?user_id={your-user-id}

Find your user_idin Streamsynq → Settings → API. It’s a UUID that scopes the lead to your account.

Headers

Content-Type: application/json
X-Streamsynq-Timestamp: {unix seconds}
X-Streamsynq-Signature: {hex HMAC-SHA256}

Every account has its own webhook secret, issued by Streamsynq when we switch the endpoint on for you. Sign each request with it: HMAC-SHA256(secret, user_id + "." + timestamp + "." + raw_body), hex-encoded. Requests more than five minutes old are rejected, and a secret only works for its ownuser_id. Both headers are required; we verify with constant-time comparison.

Body schema

{
  "source": "realtor_com" | "zillow" | "facebook"
          | "google_ads" | "idx" | "manual" | "other",
  "source_lead_id": "string (max 255, optional)",
  "name": "string (max 255, optional)",
  "email": "string (RFC-valid, optional)",
  "phone": "string (E.164 format, optional)",
  "property_address": "string (max 500, optional)",
  "property_mls_number": "string (max 100, optional)",
  "property_price": number (optional),
  "inquiry_message": "string (max 5000, optional)",
  "buyer_or_seller": "buyer" | "seller" | "unknown",
  "timeline": "string (max 100, optional)",
  "consent_captured_at": "ISO-8601 (optional, see below)",
  "consent_text": "string (optional, the consent language shown)",
  "metadata": { "any": "key-values you want stored" }
}

Validation via Zod. Invalid payloads return 400 with the field-level errors.

Before Robyn contacts a lead, the payload has to show the person asked to hear from you. One of: a portal source (zillow / realtor_com) with the portal’s own source_lead_id; an inquiry_message the lead actually wrote; or consent_captured_at plus the consent_textthey agreed to on your form. A bare name and phone number is stored in your pipeline for you to work by hand — it is never texted or dialed.

Sample request

curl -X POST 'https://streamsynq.io/api/webhooks/lead?user_id=YOUR-UUID' \
  -H 'Content-Type: application/json' \
  -H 'X-Streamsynq-Timestamp: 1788696000' \
  -H 'X-Streamsynq-Signature: 3f9a…(hex HMAC-SHA256)' \
  -d '{
    "source": "realtor_com",
    "source_lead_id": "RDC-8841923",
    "name": "Aiden Park",
    "email": "aiden.park@gmail.com",
    "phone": "+18135552001",
    "property_address": "4521 Bayshore Blvd, Tampa FL 33611",
    "inquiry_message": "Saw your listing — wondering about HOA fees",
    "buyer_or_seller": "buyer",
    "timeline": "0-30d"
  }'

Response

200 OK
{
  "ok": true,
  "lead_id": "uuid-here",
  "orchestrator_action": "call_initiated" | "skipped",
  "orchestrator_reason": "no_phone_number" | null
}

Errors

  • 400Missing or invalid user_id, malformed JSON, or schema validation failure.
  • 401Missing, stale (>5 min), or invalid X-Streamsynq-Timestamp / X-Streamsynq-Signature.
  • 403This account's webhook hasn't been switched on yet — email support@streamsynq.io to get your secret.
  • 429More than 60 leads in an hour for one account. Back off and retry after the Retry-After header.
  • 500Internal error. We log every 500 to Sentry — if you see one consistently, email support@streamsynq.io with the request ID from the response.

Retry policy

We recommend retrying on 5xx responses with exponential backoff (1s, 2s, 4s, 8s, 16s) up to 5 attempts. Use the source_lead_id field to ensure idempotency — duplicate posts of the same source_lead_id return the existing lead instead of creating a new one.

Need a custom integration?

We’ll build a custom adapter for your CRM if you bring us the customer.

Email us →