← back to integrations

Integration Guide

Wire Benji into your stack — incoming leads, outbound events, and everything in between. Print or save as PDF for offline.

Generate API keys →
§1

Authentication

Every Benji webhook + API call authenticates with a Bearer token you generate in Settings → Integrations → API & Webhooks. Keys start with benji_ and are scoped per-user.

Generate a key

  1. Sign in to Benji and go to Settings → Integrations → API & Webhooks.
  2. Click Create key. Pick a label like "Zapier" or "Make" so you can identify it in logs later.
  3. Copy the key immediately. Benji shows it once; after that you can revoke it but not retrieve it.

Using the key

Pass the key in the Authorization header:

Authorization: Bearer benji_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

Limits

  • 30 requests per minute per key. Higher tiers available on request.
  • Keys never expire by default — rotate manually when staff turns over.
  • Revoked keys are rejected immediately with a 401 + code: "revoked".
§2

Incoming webhooks

One endpoint creates a new lead in Benji and (optionally) a loan attached to that lead, with the LO who owns the API key as the recipient. Triggers AI SMS nurturing + cadences automatically.

POST https://benji.biz/api/webhooks/leads
Authorization: Bearer benji_xxxxxxxx
Content-Type: application/json

Minimum payload

{
  "firstName": "Sarah",
  "lastName": "Whitman",
  "email": "sarah@example.com",
  "phone": "+1 612 555 0100",
  "source": "Facebook Lead Ads"
}

Full payload (everything you can send)

{
  "firstName": "Sarah",
  "lastName": "Whitman",
  "email": "sarah@example.com",
  "phone": "+1 612 555 0100",
  "source": "Facebook Lead Ads — Spring Refi",

  // Free-text — lands in the lead's Notes section.
  // Aliases: "message" and "comments" are also accepted.
  "notes": "Looking at a $485k purchase in Maple Grove",

  // Optional structured fields. All optional.
  "state": "MN",
  "program": "Refinance",
  "loanType": "CONVENTIONAL",
  "loanAmountRange": "300K_TO_500K",
  "creditScoreRange": "SCORE_740_759",

  // Free-form JSON. Stamp anything you want — read back from the
  // Client's metadata. Useful for dedup keys (Meta fb_lead_id),
  // form IDs, campaign tracking.
  "metadata": {
    "fb_lead_id": "1234567890",
    "fb_form_id": "987654321",
    "fb_campaign_id": "abc123"
  },

  // Optional: create a loan in the same request.
  "loan": {
    "loanType": "CONVENTIONAL",
    "loanPurpose": "PURCHASE",
    "loanAmount": 485000,
    "propertyType": "SINGLE_FAMILY",
    "purchasePrice": 525000,
    "downPayment": 40000,
    "interestRate": 6.625
  }
}

Response

HTTP 201
{
  "success": true,
  "clientId": "cl_abc123…",
  "message": "Lead \"Sarah Whitman\" created successfully",
  "pipelineStage": "LEAD",
  "leadDisposition": "NEW",
  "noteId": "n_def456…",
  "loanId": "ln_ghi789…"
}

What fires automatically

  • AI SMS nurturing— if enabled on the LO's account, the first text fires within seconds.
  • Cadence triggers — any cadence subscribed toINBOUND_WEBHOOK events (filterable by source tag).
  • Outgoing webhooks — any subscriber to CLIENT_CREATEDgets fired with the new client's payload. See §4.
  • In-app + email + SMS notification to the LO (per their per-category notification preferences).
§3

Recipes

End-to-end setup paths for the most common lead sources. Each is ~5 minutes once you have an API key.

Meta Lead Ads → Benji (via Zapier)

Pipe every Facebook lead form submission directly into Benji. AI SMS texts within seconds of submit.

  1. In Benji: Settings → Integrations → API & Webhooks→ create a key labeled "Zapier".
  2. In Zapier: Create → New Zap. Trigger: Facebook Lead Ads → New Lead. Connect your FB ad account, pick the Page + Lead Form.
  3. Action: Webhooks by Zapier → POST. URL: https://benji.biz/api/webhooks/leads. Payload type: JSON. Paste the template from §2 above, replacing each value with the Meta field picker.
  4. Headers: Authorization: Bearer benji_xxxx, Content-Type: application/json.
  5. Test, then publish.
Tip:if your form has a single "Full Name" field, use Zapier's Formatter → Split Text on space to split into firstName and lastName before the POST step.

Custom web form → Benji

If you control the form's backend, post directly — no middleware needed. curl example:

curl -X POST https://benji.biz/api/webhooks/leads \
  -H "Authorization: Bearer benji_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Sarah",
    "lastName": "Whitman",
    "email": "sarah@example.com",
    "phone": "+1 612 555 0100",
    "source": "Marketing site — Hero CTA"
  }'

Arive LOS → Benji (native sync)

Native Zapier-driven sync. Every Arive loan auto-creates or upserts a Benji client + loan, idempotent by sysGUID. Full setup walkthrough lives at benji.biz/integrations (and the in-app Settings → Arive card after you sign up).

Calendly → Benji (native)

OAuth integration — connect once in Settings → Integrations, and every Calendly booking appears on the Benji calendar with the right client attached.

n8n / Make / generic — same shape

Any tool that can POST JSON with a Bearer header works. The payload shape from §2 is the contract. Make and n8n have identical setup steps to Zapier — Webhook node, POST, JSON body, two headers. No special connectors needed.

§4

Outgoing webhooks

Subscribe to Benji events from your backend. Useful for syncing into a data warehouse, firing third-party automations, or keeping a backup CRM in sync.

Subscribe

Settings → Integrations → Outgoing webhooks → Add endpoint. Pick a URL, choose which events to subscribe to, optionally provide a signing secret.

Event types

EventFires when
CLIENT_CREATEDAny new client/lead — in-app + API + Arive sync
CLIENT_UPDATEDDisposition / stage / contact field change
CLIENT_DELETEDLO permanently removes a client
LOAN_CREATEDNew loan attached to a client
LOAN_STAGE_CHANGEDLoan moves to a new pipeline stage
LOAN_FUNDEDLoan reaches FUNDED status
APPOINTMENT_BOOKEDCalendar event added (Calendly or in-app)
NOTE_ADDEDLO or AI adds a note to a client
SMS_RECEIVEDBorrower replies to a Benji-sent SMS

Signed payloads

When you set a signing secret, every delivery includes anX-Benji-Signature header — an HMAC-SHA256 of the raw body using your secret. Verify before trusting the payload.

// Node.js example
import crypto from "crypto";

function verifyBenjiSignature(body, header, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(header)
  );
}

Retries

Failed deliveries retry with exponential backoff for up to 24 hours. Persistent failures mark the endpoint inactive — you'll see this in Settings → Outgoing webhooks with a button to reactivate.

§5

Field reference

The fields you can write to via the incoming webhook + the enum values they accept. Anything not listed is rejected with a 422.

Required (always)

firstName · lastName

Recommended

email · phone · source

Client fields (all optional)

statestring (2-letter US state code)
programFree text — e.g. "Refinance", "Purchase"
loanTypeCONVENTIONAL | FHA | VA | USDA | JUMBO | NON_QM | HELOC
loanAmountRangeUNDER_100K | RANGE_100K_TO_300K | RANGE_300K_TO_500K | RANGE_500K_TO_750K | RANGE_750K_TO_1M | OVER_1M
creditScoreRangeSCORE_BELOW_600 | SCORE_600_619 | SCORE_620_639 | … | SCORE_800_PLUS
notes / message / commentsFree text — lands in client.Notes
metadataArbitrary JSON object — for dedup IDs, source tracking

Loan block (optional)

loanType(required if loan block present) — same enum as above
loanPurposePURCHASE | REFINANCE | CASH_OUT_REFI | HELOC | CES
loanAmountnumber
propertyTypeSINGLE_FAMILY | MULTI_FAMILY | CONDO | TOWNHOUSE | MANUFACTURED | LAND
occupancyTypePRIMARY | SECOND_HOME | INVESTMENT
purchasePrice / downPaymentnumber
interestRatedecimal (6.75) or percent-form (0.0675) — both accepted
loanTermMonthsnumber — 120, 180, 240, 360, 480
closingDateISO 8601 date
§6

Common gotchas

  • Phone format: any reasonable shape works ("+1 612 555 0100", "612-555-0100", "(612) 555-0100"). Benji normalizes to E.164 internally. If your form lets users type freely, we'll handle the cleanup.
  • Enum case: enum values are SCREAMING_SNAKE_CASE. Lowercase or mixed case returns a 422.
  • Phone & email both empty:the request still succeeds, but the AI SMS nurturing won't fire (nothing to text). For best results, require at least one of phone/email on your intake form.
  • Rate limit (429): the response includes aRetry-After header in seconds. Your client should respect it — bursting through the rate limit gets the key throttled longer.
  • Idempotency: the incoming endpoint creates a new client per request. If your source might fire twice (Meta Lead Ads occasionally does), dedupe on metadata.fb_lead_id on your side before posting.
  • Team routing:if your account is on a Brokerage team with round-robin or owner-only lead routing enabled, the lead lands on the routed LO — not necessarily the API key owner. The response always returns the routed owner's clientId.
§7

Help & support

  • In-app:click the floating life-buoy button on any dashboard page. Reports include the URL you're on + the record you're viewing automatically.
  • Email: reply to any Benji email — replies route to support directly.
  • Webhook logs: every incoming + outgoing webhook delivery is logged for 30 days. View the last 100 in Settings → Integrations → API & Webhooks → Logs.