# קבלת לידים

נקודת קליטה היא כתובת פרטית שהופכת שליחת טופס או שלב באוטומציה לליד ב-banta. לא צריך מפתח API ולא צריך לכתוב קוד: מדביקים את הכתובת בתוסף הטפסים או בפלטפורמת האוטומציה, וכל שליחה הופכת לליד.

יוצרים נקודת קליטה לכל מקור - למשל "טופס צור קשר באתר" או "Facebook דרך Zapier" - ב-banta, תחת **הגדרות ← חיבורים וטכנולוגיה ← Webhooks ← קבלת לידים**. לכל נקודה ברירות מחדל משלה: מקור ליד, סטטוס, אחראי, תגיות וטיפול בכפילויות. לארגון יכולות להיות עד 20 נקודות קליטה.

## הכתובת

| כתובת | מתי משתמשים בה |
|---|---|
| `https://app.banta.co.il/hooks/leads/<token>` | מומלצת |
| `https://db.banta.co.il/functions/v1/lead-intake/<token>` | חובה כשהנקודה מוגבלת לכתובות IP |

- הטוקן (`blh_...`) מוצג **פעם אחת בלבד**, ביצירת הנקודה. שמרו על הכתובת כמו על סיסמה. אם היא דלפה, חדשו את הטוקן ב-banta - הכתובת הישנה מפסיקה לעבוד מיד.
- שולחים בקשות `POST` משרת או מפלטפורמת אוטומציה בלבד. הנקודה לא מקבלת בקשות מדפדפן (CORS) - טופס ששולח ישירות מדף אינטרנט היה חושף את הטוקן. לטופס שמוטמע באתר משתמשים בטפסים הציבוריים של banta.

## בקשות נתמכות

- **JSON** - אובייקט, או מערך עם אובייקט אחד בדיוק. אובייקטים מקוננים נתמכים.
- **`application/x-www-form-urlencoded`** - כולל מפתחות עם סוגריים, כמו `fields[name][value]`.
- **`multipart/form-data`** - שדות טקסט בלבד; קבצים לא נקלטים.

ליד אחד לבקשה, עד 64KB.

## אבטחה

| שכבה | פירוט |
|---|---|
| טוקן סודי | חלק מהכתובת. פעיל תמיד. |
| רשימת כתובות IP מורשות | אופציונלי. כתובות בודדות או טווחי CIDR, IPv4 ו-IPv6. עובד רק עם הכתובת `db.banta.co.il` - הכתובת `https://app.banta.co.il` עוברת דרך proxy שמסתיר את כתובת השולח. |
| חתימה | אופציונלי. כל בקשה חייבת להיות חתומה ב-HMAC-SHA256 - פירוט בהמשך. |
| Honeypot | אופציונלי. מגדירים שם של שדה מוסתר בטופס, או משתמשים ב-`_hp` או `honeypot`. שליחה שבה השדה מולא מקבלת `200` ונזרקת. |
| מגבלות קצב | 300 בקשות ל-10 דקות לכל נקודה. |

### חתימה על בקשות

כשמפעילים חתימה, banta מציגה סוד חתימה פעם אחת. כל בקשה חייבת לכלול שתי כותרות:

- `X-Banta-Timestamp` - זמן Unix נוכחי, בשניות.
- `X-Banta-Signature` - `sha256=` ואחריו ה-HMAC-SHA256 בהקסדצימלי (אותיות קטנות) של `<timestamp>.<הגוף הגולמי>`, עם סוד החתימה כולו כמפתח.

בקשה שחותמת הזמן שלה רחוקה ביותר מ-5 דקות משעון השרת נדחית. חותמים על הבייטים המדויקים שנשלחים. זו אותה שיטה ש-banta משתמשת בה ב-[webhooks יוצאים](https://docs.banta.co.il/he/guides/webhooks.md).

**Node.js 18+**

```js
import crypto from 'node:crypto'

const url = 'https://app.banta.co.il/hooks/leads/blh_...'
const body = JSON.stringify({ first_name: 'Noa', last_name: 'Bar', phone: '0541234567', email: 'noa@example.com' })
const timestamp = Math.floor(Date.now() / 1000).toString()
const signature = crypto
  .createHmac('sha256', process.env.BANTA_SIGNING_SECRET)
  .update(`${timestamp}.${body}`)
  .digest('hex')

const res = await fetch(url, {
  method: 'POST',
  body,
  headers: {
    'Content-Type': 'application/json',
    'X-Banta-Timestamp': timestamp,
    'X-Banta-Signature': `sha256=${signature}`,
    'Idempotency-Key': 'crm-lead-12345',
  },
})
console.log(res.status, await res.json())
```

**Python**

```python
import hashlib, hmac, json, os, time
import requests

url = "https://app.banta.co.il/hooks/leads/blh_..."
body = json.dumps({"first_name": "Noa", "phone": "0541234567"}, ensure_ascii=False)
timestamp = str(int(time.time()))
signature = hmac.new(
    os.environ["BANTA_SIGNING_SECRET"].encode(),
    f"{timestamp}.{body}".encode(),
    hashlib.sha256,
).hexdigest()

r = requests.post(url, data=body.encode("utf-8"), headers={
    "Content-Type": "application/json",
    "X-Banta-Timestamp": timestamp,
    "X-Banta-Signature": f"sha256={signature}",
})
print(r.status_code, r.json())
```

**PHP / WordPress**

```php
<?php
// Define BANTA_SIGNING_SECRET in wp-config.php
$body      = wp_json_encode(['first_name' => 'Noa', 'phone' => '0541234567']);
$timestamp = (string) time();
$signature = hash_hmac('sha256', $timestamp . '.' . $body, BANTA_SIGNING_SECRET);

$response = wp_remote_post('https://app.banta.co.il/hooks/leads/blh_...', [
    'headers' => [
        'Content-Type'      => 'application/json',
        'X-Banta-Timestamp' => $timestamp,
        'X-Banta-Signature' => 'sha256=' . $signature,
    ],
    'body'    => $body,
    'timeout' => 10,
]);
```

לבדיקת המימוש שלכם - הקלט הזה חייב להפיק את החתימה הזו:

| | |
|---|---|
| סוד | `blhsec_0123456789abcdef0123456789abcdef0123456789abcdef` |
| חותמת זמן | `1760443200` |
| גוף | `{"first_name":"Noa","phone":"0541234567"}` |
| חתימה | `sha256=36423b4bb8b14256ffc3bf36d62c27f96fe90accc76eef115d5fbeafb3694111` |

תוספי טפסים לא יודעים לחתום על בקשות. עבורם מסתמכים על הכתובת הסודית, ואם לשרת שלכם יש כתובת קבועה - מוסיפים רשימת IP.

## צעד אחר צעד

### Elementor Pro

1. עורכים את הטופס, ותחת **Actions After Submit** מוסיפים **Webhook**.
2. בקטע **Webhook** מדביקים את כתובת הנקודה.
3. **Advanced Data** יכול להיות מופעל או כבוי - שני הפורמטים נתמכים.
4. מעדכנים את העמוד ושולחים טופס לבדיקה.

מזהי שדות של Elementor כמו `name`, `email` ו-`message`, ותוויות כמו "טלפון" או "Phone", מזוהים אוטומטית. שדה עם מזהה אקראי (`field_3f2a1b`) מזוהה לפי התווית שלו כשהיא אחד מהשמות המובנים; אחרת ממפים אותו לפי המזהה או התווית. banta מחזירה `200` בהצלחה, כפי ש-Elementor דורש, הרבה בתוך מגבלת 5 השניות שלו.

### Contact Form 7

ל-Contact Form 7 נדרש תוסף webhook, למשל "CF7 to Webhook".

1. עורכים את הטופס ופותחים את לשונית **Webhook** של התוסף.
2. מפעילים, מדביקים את כתובת הנקודה ושומרים.

שדות ברירת המחדל `your-name`, `your-email`, `your-tel` ו-`your-message` מזוהים. שדות אחרים נשמרים בהערת הפרטים של הליד, אלא אם ממפים אותם.

### WPForms

נדרש התוסף **Webhooks** של WPForms.

1. בעורך הטופס נכנסים ל-**Settings ← Webhooks** ומפעילים webhooks.
2. מוסיפים webhook עם כתובת הנקודה, שיטה `POST` ופורמט `JSON`.
3. ב-**Request Body** מוסיפים שורה לכל שדה: המפתח הוא שם השדה ב-banta (`first_name`, `last_name`, `phone`, `email`, `notes`), והערך הוא שדה הטופס.

### Gravity Forms

נדרש **Webhooks Add-On** של Gravity Forms.

1. נכנסים ל-**Form Settings ← Webhooks ← Add New**.
2. מגדירים את כתובת הנקודה, שיטה `POST` ופורמט `JSON`.
3. בגוף הבקשה בוחרים **Select Fields** עם שמות השדות ב-banta כמפתחות, או **All Fields**.

ב-**All Fields** נשלחים מזהים מספריים של השדות - למשל `1.3` (שם פרטי), `1.6` (שם משפחה) ו-`2` (אימייל). ממפים אותם במיפוי השדות של הנקודה. נתוני הרשומה של Gravity (מזהה רשומה, כתובת IP, דפדפן, תאריכים) מושמטים אוטומטית.

### Zapier

1. מוסיפים פעולה **Webhooks by Zapier ← POST**.
2. **URL**: כתובת הנקודה. **Payload Type**: `json`.
3. ב-**Data** המפתחות הם שמות השדות ב-banta (`first_name`, `phone`, `email`, `utm_source`...).

### Make

1. מוסיפים מודול **HTTP ← Make a request**.
2. **URL**: כתובת הנקודה. **Method**: `POST`.
3. **Body type**: `Raw`. **Content type**: `JSON (application/json)`. **Request content**: אובייקט JSON עם שמות השדות ב-banta.

### Facebook Lead Ads (דרך Zapier או Make)

1. טריגר: **Facebook Lead Ads ← New Lead**. פעולה: **Webhooks by Zapier ← POST** (או מודול ה-HTTP של Make).
2. ממפים את **Full Name**, **Phone Number** ו-**Email** ל-`full_name`, `phone` ו-`email` - או שולחים את הליד כולו.

המערך `field_data` של Facebook ו-`campaign_name` (שנשמר כ-`utm_campaign`) מזוהים. שמות המודעה, קבוצת המודעות והטופס נשמרים בהערת הפרטים של הליד. שאלות מותאמות ממפים במיפוי השדות - למשל `האם_יש_לך_נכס?` ל-`has_property`.

## מיפוי שדות

כל שדה נכנס עובר התאמה בסדר הזה:

1. מיפוי השדות של הנקודה, לפי מפתח השדה או התווית שלו.
2. השמות המובנים שבטבלה למטה. ההתאמה מתעלמת מאותיות גדולות וקטנות, מההבדל בין רווח, מקף וקו תחתון, ומ-`*` או `:` בסוף השם. ב-JSON מקונן מותאם החלק האחרון של הנתיב.
3. שדות טכניים של פלטפורמות הטפסים (למשל נתוני הטופס של Elementor, נתוני הרשומה של Gravity, טוקנים של captcha ומפתחות שמתחילים ב-`_`) מושמטים.
4. כל השאר נשמר בהערת פרטים על הליד, כך ששום דבר שהגולש הקליד לא הולך לאיבוד.

| שדה ב-banta | שמות מזוהים |
|---|---|
| `first_name` | first_name, firstname, first name, fname, first, given_name, שם פרטי, פרטי |
| `last_name` | last_name, lastname, last name, lname, last, surname, family_name, שם משפחה, משפחה |
| `full_name` | name, full_name, fullname, your-name, contact_name, שם, שם מלא, שם ושם משפחה, שם הלקוח |
| `phone` | phone, tel, mobile, telephone, phone_number, phonenumber, your-tel, your-phone, cell, cellphone, mobile_phone, whatsapp, טלפון, נייד, טלפון נייד, מספר טלפון, מספר נייד, פלאפון, סלולרי |
| `email` | email, e-mail, mail, email_address, your-email, אימייל, דוא"ל, דואל, מייל, דואר אלקטרוני, כתובת מייל |
| `notes` | message, notes, note, comments, comment, your-message, details, inquiry, enquiry, הודעה, הערות, הערה, פרטים, תוכן ההודעה, תוכן הפנייה, פנייה |
| `source` | source, lead_source, how_did_you_hear, מקור, מקור הגעה, מקור הליד, איך שמעת עלינו, איך הגעת אלינו |
| `mortgage_purpose` | mortgage_purpose, purpose, loan_purpose, מטרת המשכנתא, מטרת משכנתא, מטרת ההלוואה, מטרה |
| `required_amount` | required_amount, amount, loan_amount, mortgage_amount, סכום, סכום משכנתא, סכום המשכנתא, סכום מבוקש, סכום הלוואה, סכום ההלוואה |
| `total_income` | total_income, income, monthly_income, הכנסה, הכנסה חודשית, הכנסות, סך הכנסות |
| `has_property` | has_property, own_property, owns_property, יש נכס, בעל נכס, האם יש נכס, בעלות על נכס |
| `utm_source` ... `utm_content` | utm_source, utm_medium, utm_campaign (וגם campaign_name), utm_term, utm_content |
| `referrer_url` | referrer, referer, referrer_url, http_referer, document_referrer |
| `landing_path` | landing_path, landing_page, page_url, source_url, form_url, page_location |

יעדי מיפוי: `first_name`, `last_name`, `full_name`, `phone`, `email`, `notes`, `source`, `source_id`, `mortgage_purpose`, `required_amount`, `total_income`, `has_property`, `next_follow_up_at`, `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content`, `referrer_url`, `landing_path`, `custom_fields.<field_name>` ו-`ignore`.

- שם מלא מתפצל לשם פרטי (המילה הראשונה) ולשם משפחה (השאר).
- חובה טלפון או אימייל. ליד בלי שם נקרא על שם הנקודה.
- מספרי טלפון מנורמלים; ישראל היא מדינת ברירת המחדל.
- מקור ליד שמופיע בבקשה גובר על מקור ברירת המחדל של הנקודה.
- הסטטוס והאחראי נקבעים תמיד לפי הגדרות הנקודה.
- יומן האירועים של הנקודה מציג את השדות של השליחות האחרונות ואת המיפוי של כל אחד מהם - הדרך הקלה לבנות מיפוי היא לשלוח טופס בדיקה אחד ולמפות מתוך היומן.

## כפילויות ושליחות חוזרות

כל נקודה קובעת מה קורה כשמגיע ליד עם טלפון או אימייל של ליד קיים:

| מצב | התנהגות |
|---|---|
| `flag` (ברירת מחדל) | הליד נוצר ומסומן ככפילות אפשרית. התגובה כוללת `duplicate_of`. |
| `reuse` | לא נוצר ליד חדש. מוחזר הליד הקיים, והפנייה החדשה נרשמת עליו כהערה. |
| `none` | ללא בדיקת כפילויות. |

שליחה חוזרת של אותה פנייה לעולם לא יוצרת ליד שני:

- שליחה זהה בתוך 10 דקות מחזירה את התוצאה המקורית עם הכותרת `Idempotent-Replayed: true`.
- כך גם בקשה שחוזרת על מפתח idempotency - הכותרת `Idempotency-Key`, או `X-Idempotency-Key`, `webhook-id` או `X-Request-Id`.
- כדי ליצור ליד בדיקה נוסף, משנים שדה כלשהו.

## בדיקה עם curl

**JSON**

```bash
curl -i -X POST "https://app.banta.co.il/hooks/leads/blh_..." \
  -H "Content-Type: application/json" \
  -d '{"full_name":"Test Lead","phone":"050-000-0000","email":"test@example.com","notes":"Sent with curl"}'
```

**שליחת טופס עם שמות שדות בעברית**

```bash
curl -i -X POST "https://app.banta.co.il/hooks/leads/blh_..." \
  --data-urlencode "שם מלא=ליד בדיקה" \
  --data-urlencode "טלפון=050-000-0000"
```

**בקשה חתומה**

```bash
URL="https://app.banta.co.il/hooks/leads/blh_..."
BODY='{"full_name":"Test Lead","phone":"050-000-0000"}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$BANTA_SIGNING_SECRET" | sed 's/^.* //')
curl -i -X POST "$URL" \
  -H "Content-Type: application/json" \
  -H "X-Banta-Timestamp: $TS" \
  -H "X-Banta-Signature: sha256=$SIG" \
  -d "$BODY"
```

כל בקשה - שהתקבלה או שנדחתה - מופיעה ביומן האירועים של הנקודה ב-banta למשך 30 יום, עם סיבת הדחייה אם הייתה.

## תגובות

| קוד | משמעות |
|---|---|
| `200` | `{"ok": true, "lead_id": "...", "created": true}`. `created: false` פירושו שליד קיים שימש מחדש. `duplicate_of: {id, lead_number}` מופיע כשנמצאה כפילות אפשרית. שליחה שנתפסה ב-honeypot מחזירה `{"ok": true}` בלבד. |
| `400` | הגוף לא תקין, או שאין בו לא טלפון ולא אימייל: `{"ok": false, "error": "...", "details": "..."}` |
| `401` | החתימה חסרה או שגויה |
| `403` | כתובת ה-IP של השולח לא מורשית, או שלארגון אין מנוי פעיל |
| `404` | הנקודה לא קיימת או מושבתת |
| `405` | שיטה שאינה `POST` |
| `409` | בקשה זהה עדיין בעיבוד - נסו שוב בעוד כמה שניות |
| `413` | הגוף גדול מ-64KB |
| `429` | יותר מדי בקשות - ראו את הכותרת `Retry-After` |
| `500` | שגיאה זמנית - נסו שוב מאוחר יותר |

כל הצלחה מחזירה `200`, גם כשנוצר ליד חדש, כי חלק מתוספי הטפסים (ביניהם Elementor Pro) מתייחסים לכל קוד אחר כשגיאה.

## מגבלות

- עד 20 נקודות קליטה לארגון.
- 300 בקשות ל-10 דקות לכל נקודה.
- עד 64KB וליד אחד לבקשה.
- נקראים 200 השדות הראשונים, וערכים נחתכים אחרי 5,000 תווים.
- חותמת הזמן של החתימה חייבת להיות בטווח של 5 דקות משעון השרת.
- יומן האירועים נשמר 30 יום.

---

חלק מתיעוד ה-API של banta. אינדקס מלא: https://docs.banta.co.il/he/llms.txt
