האתר משתמש בעוגיות הכרחיות לתפעולו ובעוגיות אנליטיקה כדי להבין כיצד משתמשים שלנו פועלים. השימוש בעוגיות אנליטיקה כפוף להסכמתך, בהתאם לחוק הגנת הפרטיות. פרטים נוספים במדיניות הפרטיות
Vibrate API Skill · v2026-08-28
העתק-הדבק אחד מלמד את ChatGPT, Claude, Claude Code, Cursor או Copilot את כל ה-API של Vibrate ל-SMS ו-WhatsApp: כל endpoint, שדה, קוד שגיאה ומלכודת. בקשו את האינטגרציה שאתם צריכים וקבלו קוד עובד.
mkdir -p .claude/skills/vibrate-api curl -fsSL https://www.vibrate.co.il/vibrate-api-skill.md -o .claude/skills/vibrate-api/SKILL.md
prompt
Read https://www.vibrate.co.il/vibrate-api-skill.md and treat it as the authoritative reference for the Vibrate SMS & WhatsApp REST API (base URL https://api.vibrate.co.il). Use only the endpoints, fields, status codes and error codes documented there - never invent others. Then help me with the following task:
https://www.vibrate.co.il/vibrate-api-skill.md
שלושה צעדים, פחות מדקה.
העתיקו את ה-Skill המלא למטה (או את הפרומפט הקצר אם העוזר שלכם יודע לפתוח קישורים).
הדביקו כהודעה הראשונה ב-ChatGPT, Claude, Cursor או Claude Code. מעכשיו זה התיעוד שהעוזר עובד לפיו.
"שלח SMS מהשרת Express שלי", "שלח את תבנית הוואטסאפ הזו לרשימה שלי", "בדוק סטטוס מסירה ושמור אותו". מקבלים קוד שמשתמש ב-endpoints האמיתיים.
Markdown פשוט. זה בדיוק מה שה-AI שלכם קורא.
mkdir -p .claude/skills/vibrate-api curl -fsSL https://www.vibrate.co.il/vibrate-api-skill.md -o .claude/skills/vibrate-api/SKILL.md
---
name: vibrate-api
description: Authoritative reference for the Vibrate SMS & WhatsApp Business REST API (api.vibrate.co.il). Use when writing code that sends SMS or WhatsApp template messages, manages distribution lists (campaigns) and contacts, or polls delivery status through Vibrate. Covers auth, every endpoint, request/response shapes, phone-number rules, billing units, error codes and known pitfalls.
version: 2026-08-28
source: https://www.vibrate.co.il/vibrate-api-skill.md
---
# Vibrate API Skill
You are helping a developer integrate the **Vibrate** messaging platform (Israel-focused SMS + WhatsApp Business API, vibrate.co.il). This document is the complete, authoritative reference. Follow it exactly:
- Use ONLY the endpoints, fields, headers, status codes and error codes listed here. Do not invent endpoints (there is no `/v1/sms/status`, no `/v1/whatsapp/text`, no `/v2`).
- Base URL: `https://api.vibrate.co.il` - all paths below are relative to it. Always HTTPS. JSON in, JSON out.
- Prefer the most specific endpoint (e.g. `sendBulk` for personalised messages to many recipients, `send` for one message to one or more recipients).
- When the user's language is Hebrew, keep message bodies in Hebrew and explain in Hebrew; keep code, field names and paths exactly as documented.
- Never use an em dash in generated copy; use a regular hyphen.
## 1. Authentication
- Every request needs an access token created in the Vibrate app at **Settings → Access Keys** (`https://www.vibrate.co.il/sms/tokens`).
- Send it in the `Authorization` header. The raw token is accepted; a `Bearer ` prefix is also accepted and stripped. `access_token` header is a legacy alias.
```http
Authorization: YOUR_ACCESS_TOKEN
Content-Type: application/json
```
- Auth failures return `401` with `code` one of `ACCESS_TOKEN_MISSING`, `ACCESS_TOKEN_INVALID`, `ACCESS_TOKEN_INACTIVE`, `USER_DELETED`, `USER_INACTIVE`.
- Tokens are per user account; all campaigns, senders, WhatsApp numbers and templates referenced in a request must belong to that account.
## 2. Response envelope
Success (2xx):
```json
{ "success": true, "data": { ... }, "message": "Human readable" }
```
Error (4xx/5xx):
```json
{
"message": "Insufficient SMS credits",
"code": "SMS_INSUFFICIENT_CREDITS",
"errors": ["..."],
"hints": "You need at least 3 SMS credits, but you only have 1 SMS credits"
}
```
- Branch on the HTTP status and on `code`, never on `message` text.
- Zod validation failures return `400` with `code: "VALIDATION_ERROR"` and `errors` = the Zod issue array (`path`, `message` per issue).
- Bodies over the limit (2 MB; 15 MB for `/v1/sms/sendBulk`) return `413 PAYLOAD_TOO_LARGE`.
## 3. Core rules (read before writing code)
### Phone numbers
- Israel is the implicit country. Accepted input forms, all normalised server-side to E.164 digits without `+`: `0501234567`, `050-123-4567`, `972501234567`, `+972501234567`, `+972 050-123-4567`.
- Foreign numbers must carry their country code with `+` or `00` (`+14155551234`, `00447911123456`) or already be in E.164 digits (`14155551234`).
- Pasted numbers often carry invisible bidi characters (U+200E, U+202C etc.). Strip non-digit / non-`+` characters client-side before sending.
- Recipients on the account's do-not-send (unsubscribe) registry are silently skipped at send time; this is by design and cannot be overridden through the API.
### Sender (SMS only)
- `sender` is REQUIRED on every SMS send and must exactly match an **active sender** on the account (an approved alphanumeric Sender ID such as `MySender`, or a phone number). Otherwise: `400 SMS_INVALID_SENDER`.
- Senders are created and approved in the Vibrate app, not via the API.
### SMS billing units
- 1 SMS unit = up to **256 characters** of the trimmed message, regardless of language or encoding (Hebrew and English cost the same). Units = `ceil(length / 256)`.
- Cost of a request = units × number of recipients. Credits are reserved atomically before queuing; if the balance is short the whole request is rejected with `400 SMS_INSUFFICIENT_CREDITS` and nothing is sent.
- Accounts may carry a rolling 24-hour message cap: `400 SMS_DAILY_LIMIT_EXCEEDED` (`hints` includes limit / used / remaining).
### Asynchronous delivery
- All send endpoints return **`202 Accepted`** once the batch is queued. A 202 means "accepted and billed", NOT "delivered". Track delivery with `GET /v1/sms/run/{runId}/delivery-status` or `GET /v1/sms/messages?runId=...`.
- Message statuses: `queued` → `in_progress` → `sent` → `delivered`, or `failed`. `statusHistory` on each message is an ordered array of `{ state, occurredAt, error?, errorCodes? }`.
### Idempotency (bulk SMS)
- `POST /v1/sms/sendBulk` accepts an optional `Idempotency-Key` header (1-255 chars, use a UUID). Retrying with the same key within 24 h replays the original 202 (response header `Idempotency-Replayed: true`) instead of sending and billing again. A retry while the first request is still running returns `409 CONFLICT`; retry after a few seconds. Failed requests release the key so a retry re-executes.
## 4. Endpoints
### 4.1 Account
#### GET /v1/user/info
Returns the account behind the token, including the SMS credit balance.
Response `200`:
```json
{ "success": true, "message": "User data retrieved successfully",
"data": { "email": "[email protected]", "name": "ישראל ישראלי", "status": "active", "smsAmount": 38 } }
```
Use `smsAmount` to pre-check credits before a large send.
### 4.2 SMS
#### POST /v1/sms/send
One message body to one or more recipients.
Body:
| field | type | required | notes |
|---|---|---|---|
| `recipients` | string[] | yes | non-empty; each a phone number (see rules) |
| `message` | string | yes | trimmed server-side; units = ceil(len/256) |
| `sender` | string | yes | active sender on the account |
| `campaignId` | string | no | tag the messages to a campaign for reporting |
```bash
curl -X POST https://api.vibrate.co.il/v1/sms/send \
-H "Authorization: YOUR_ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"recipients":["0501231234"],"message":"שלום עולם","sender":"MySender"}'
```
Response `202`:
```json
{ "success": true, "message": "SMS batch queued successfully", "data": { "runId": "6d3c80fc-e2c6-4593-b787-cecafcf84f4b" } }
```
Errors: `400 VALIDATION_ERROR | SMS_NO_RECIPIENTS | SMS_INVALID_SENDER | SMS_DAILY_LIMIT_EXCEEDED | SMS_INSUFFICIENT_CREDITS`, `401`.
#### POST /v1/sms/sendBulk
Different message per recipient (personalised sends). One `sender` for the whole batch. Body limit 15 MB. Supports `Idempotency-Key`.
Body:
| field | type | required | notes |
|---|---|---|---|
| `messages` | { recipient: string, message: string }[] | yes | non-empty |
| `sender` | string | yes | active sender |
| `campaignId` | string | no | |
```bash
curl -X POST https://api.vibrate.co.il/v1/sms/sendBulk \
-H "Authorization: YOUR_ACCESS_TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: 3f1c2b7e-8d1a-4a4c-9d3e-0a1b2c3d4e5f" \
-d '{"sender":"MySender","messages":[{"recipient":"0501231234","message":"הודעה ראשונה"},{"recipient":"0505675678","message":"הודעה שנייה"}]}'
```
Response `202`: same shape as `/send` (`data.runId`). Errors as `/send` plus `400 INVALID_DATA_FORMAT` (bad Idempotency-Key), `409 CONFLICT`, `413 PAYLOAD_TOO_LARGE`.
#### GET /v1/sms/messages
Paginated message log for the account, newest first.
Query params (all optional): `status` (queued|in_progress|sent|delivered|failed), `runId`, `recipient` (substring match), `startDate`, `endDate` (ISO-8601, filter on createdAt), `page` (default 1), `limit` (default 10). `page`/`limit` must be positive integers or you get `400 MISSING_REQUIRED_FIELDS`.
Response `200`:
```json
{ "success": true, "message": "Messages retrieved successfully",
"data": {
"messages": [ { "id": "...", "recipient": "972501231234", "message": "...", "sender": "MySender", "runId": "...", "status": "delivered", "providerId": "...", "statusHistory": [ { "state": "queued", "occurredAt": "2025-06-16T21:25:19.903Z" } ], "createdAt": "...", "updatedAt": "..." } ],
"pagination": { "total": 120, "page": 1, "limit": 10, "totalPages": 12 } } }
```
#### GET /v1/sms/run/{runId}/delivery-status
Delivery summary for one send (the `runId` returned by any send endpoint). `404 RESOURCE_NOT_FOUND` if the run has no messages for this account.
Response `200`:
```json
{ "success": true, "message": "Run delivery status retrieved successfully",
"data": {
"runId": "...", "allDelivered": false,
"summary": { "total": 3, "delivered": 2, "pending": 1 },
"deliveryTimes": [ { "messageId": "...", "recipient": "972501231234", "deliveredAt": "2025-06-16T21:26:02.000Z", "status": "delivered" } ],
"nonDeliveredMessages": [ { "messageId": "...", "recipient": "972505675678", "status": "sent", "lastUpdated": "..." } ] } }
```
`nonDeliveredMessages` is omitted when everything is delivered. Poll with backoff (e.g. every 10-30 s); delivery receipts typically arrive within seconds to a few minutes.
### 4.3 Campaigns (distribution lists)
A **campaign** is a named contact list owned by the account. Contacts carry `name`, `phoneNumber` and free-form `additionalFields` used for personalisation.
#### GET /v1/sms/campaigns
Response `200`: `data` = array of `{ id, name, status, userId, createdAt, updatedAt }`.
#### POST /v1/sms/campaigns
Body: `{ "name": string }` (required, non-empty). Response `201`: `data` = the campaign object above.
#### GET /v1/sms/campaigns/{campaignId}/contacts
Response `200`: `data` = array of contacts `{ id, name, phoneNumber, additionalFields, status, campaignId, createdAt, updatedAt }`.
#### POST /v1/sms/campaigns/{campaignId}/contacts
Body:
| field | type | required |
|---|---|---|
| `phoneNumber` | string | yes |
| `name` | string | yes |
| `additionalFields` | object (string → any) | no |
```json
{ "name": "David Beckham", "phoneNumber": "0505975550", "additionalFields": { "first name": "David", "last name": "Beckham" } }
```
Response `201`: `data` = the created contact. `404` if the campaign is not yours.
#### DELETE /v1/sms/campaigns/{campaignId}/contacts/{contactId}
Response `200` `{ success: true, message: "Contact removed from campaign successfully" }`.
#### POST /v1/sms/campaigns/{campaignId}/run
Send one templated SMS to every **active** contact in the campaign; personalisation happens server-side per contact.
Body:
| field | type | required | notes |
|---|---|---|---|
| `sender` | string | yes | active sender |
| `message` | string | yes | template; `{{name}}` → contact.name, `{{<additionalField key>}}` → that field |
| `addUnsubscribe` | boolean | no (default false) | appends `<unsubscribeText> https://www.vibrate.co.il/r/<contactId>` to each message |
| `nameVar` | string | no | rename the placeholder that maps to contact.name (default `name`) |
| `unsubscribeText` | string | no | label before the unsubscribe link (default `Unsubscribe:`) |
```json
{ "sender": "MySender", "message": "שלום {{name}}, יש לך הזמנה חדשה!", "addUnsubscribe": true, "unsubscribeText": "להסרה:" }
```
Response `202`:
```json
{ "success": true, "message": "Campaign run queued successfully",
"data": { "runId": "...", "campaignId": "...", "recipientCount": 247, "totalSmsUnits": 247 } }
```
Errors: `400 VALIDATION_ERROR | SMS_INVALID_SENDER | CAMPAIGN_NO_ACTIVE_CONTACTS | SMS_DAILY_LIMIT_EXCEEDED | SMS_INSUFFICIENT_CREDITS`, `404 CAMPAIGN_NOT_FOUND`. The unsubscribe suffix counts toward the 256-char units.
### 4.4 WhatsApp
WhatsApp sends go through Meta's Cloud API. Only **approved templates** can be sent through this API (free-text replies are handled in the Vibrate inbox / chatbot, not here).
- `whatsappNumberId`: ID of a WhatsApp number connected to the account - copy it from **WhatsApp → Numbers** (`https://www.vibrate.co.il/whatsapp/numbers`).
- `templateId`: ID of an approved template - copy it from **WhatsApp → Templates** (`https://www.vibrate.co.il/whatsapp/templates`). Both are Vibrate IDs, not Meta IDs.
- Variables are positional: a template body "שלום {{1}}, ההזמנה {{2}} נשלחה" needs `bodyVariables: ["דוד", "ORD-12345"]`. Counts must match the template exactly.
- Header types: TEXT (may use `headerVariables`), IMAGE / VIDEO / DOCUMENT (require a publicly reachable `headerMediaUrl`; Meta fetches it).
#### POST /v1/whatsapp/template/send
Body:
| field | type | required | notes |
|---|---|---|---|
| `whatsappNumberId` | string | yes | |
| `templateId` | string | yes | |
| `recipient` | string | yes | phone, any accepted form |
| `bodyVariables` | string[] | no | one per `{{n}}` in the body, in order |
| `headerVariables` | string[] | no | for TEXT headers with variables |
| `headerMediaUrl` | string | no | public URL for IMAGE/VIDEO/DOCUMENT headers |
| `buttonVariables` | string[] | no | one per dynamic-URL button (`https://x.com/{{1}}`), replaces the placeholder only |
```bash
curl -X POST https://api.vibrate.co.il/v1/whatsapp/template/send \
-H "Authorization: YOUR_ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{"whatsappNumberId":"your-whatsapp-number-id","templateId":"your-template-id","recipient":"0501234567","bodyVariables":["דוד","ORD-12345"]}'
```
Response `200`:
```json
{ "success": true, "statusCode": 200, "message": "WhatsApp template sent successfully",
"data": { "messageId": "wamid.HBgLOTcyNTA...", "recipient": "972501234567" } }
```
Errors (`400`): `MISSING_REQUIRED_FIELDS`, `INVALID_TEMPLATE` / `WHATSAPP_TEMPLATE_NOT_FOUND` / `WHATSAPP_TEMPLATE_NOT_APPROVED`, `INVALID_PHONE`, `MISSING_VARIABLES` / `WHATSAPP_INVALID_VARIABLES`, `INVALID_MEDIA_URL`, `INVALID_WHATSAPP_NUMBER` / `WHATSAPP_NUMBER_NOT_FOUND`; `WHATSAPP_SEND_FAILED` / `WHATSAPP_GATEWAY_ERROR` for upstream Meta failures.
#### POST /v1/whatsapp/template/sendBulk
Send a template to every contact in a campaign (distribution list), mapping variables from contact fields. Runs in the background.
Body:
| field | type | required | notes |
|---|---|---|---|
| `whatsappNumberId` | string | yes | |
| `templateId` | string | yes | |
| `campaignId` | string | yes | the distribution list |
| `bodyMappings` | { type: "field" \| "custom", value: string }[] | no | positional; `field` reads `name` or `additionalFields.<key>` from each contact, `custom` is a fixed string |
| `headerMappings` | same shape | no | for TEXT header variables |
| `headerMediaUrl` | string | no | |
| `resumeBatchId` | string | no | re-run a previous batch, skipping contacts already sent/delivered/read |
```json
{ "whatsappNumberId": "your-whatsapp-number-id", "templateId": "your-template-id", "campaignId": "your-campaign-id",
"bodyMappings": [ { "type": "field", "value": "name" }, { "type": "custom", "value": "20% הנחה" } ] }
```
Response `202`:
```json
{ "success": true, "statusCode": 202, "message": "Bulk WhatsApp send started in background", "data": { "batchId": "batch_abc123", "totalCount": 2 } }
```
Keep `batchId`; pass it as `resumeBatchId` to safely retry a partially failed batch without double-sending.
## 5. Error code reference
| HTTP | code | meaning / fix |
|---|---|---|
| 400 | VALIDATION_ERROR | body failed schema; read `errors[]` |
| 400 | MISSING_REQUIRED_FIELDS | a required field or query param is missing/invalid |
| 400 | INVALID_DATA_FORMAT | e.g. malformed Idempotency-Key |
| 400 | SMS_NO_RECIPIENTS | `recipients` empty |
| 400 | SMS_INVALID_SENDER | `sender` missing or not an active sender on this account |
| 400 | SMS_INSUFFICIENT_CREDITS | top up credits; nothing was sent or charged |
| 400 | SMS_DAILY_LIMIT_EXCEEDED | 24 h cap reached; `hints` tells when it resets |
| 400 | CAMPAIGN_NO_ACTIVE_CONTACTS | list is empty or all contacts inactive/unsubscribed |
| 401 | ACCESS_TOKEN_MISSING / ACCESS_TOKEN_INVALID / ACCESS_TOKEN_INACTIVE | fix the Authorization header / create a new key |
| 401 | USER_INACTIVE / USER_DELETED | account problem; contact Vibrate support |
| 404 | CAMPAIGN_NOT_FOUND / RESOURCE_NOT_FOUND | wrong ID or belongs to another account |
| 409 | CONFLICT | same Idempotency-Key still in flight; retry shortly |
| 413 | PAYLOAD_TOO_LARGE | split the batch |
| 5xx | SERVER_ERROR / SMS_GATEWAY_ERROR / SMS_GATEWAY_TIMEOUT / WHATSAPP_GATEWAY_ERROR | transient; retry with backoff and (for bulk SMS) the same Idempotency-Key |
## 6. Recommended integration pattern
1. On startup / before big sends: `GET /v1/user/info` → check `smsAmount` ≥ recipients × units.
2. Normalise phones and de-duplicate recipients client-side.
3. Send with `/v1/sms/sendBulk` + `Idempotency-Key` (or `/send` for a single body). Store the returned `runId`.
4. Poll `GET /v1/sms/run/{runId}/delivery-status` with backoff until `allDelivered` or a timeout you choose (e.g. 30 min); persist per-recipient status.
5. Handle `400` codes as permanent (fix input), `409/5xx` as retryable.
6. For WhatsApp, verify the template is APPROVED and the variable counts match before sending; re-runs use `resumeBatchId`.
## 7. Things this API does NOT do
- No inbound-message or delivery **webhooks** for API customers (poll the delivery-status endpoint).
- No free-text WhatsApp sends, no sender/number/template creation, no credit purchase via API - all of that is done in the Vibrate web app (https://www.vibrate.co.il).
- No rate-limit header is returned; keep concurrency modest (a few parallel requests) and batch through `sendBulk` instead of looping `/send`.
## 8. Minimal client (TypeScript)
```ts
const BASE = "https://api.vibrate.co.il";
const headers = { Authorization: process.env.VIBRATE_TOKEN!, "Content-Type": "application/json" };
export async function sendSms(recipients: string[], message: string, sender: string) {
const res = await fetch(`${BASE}/v1/sms/send`, { method: "POST", headers, body: JSON.stringify({ recipients, message, sender }) });
const json = await res.json();
if (!res.ok) throw new Error(`${json.code}: ${json.message} (${json.hints ?? ""})`);
return json.data.runId as string;
}
export async function deliveryStatus(runId: string) {
const res = await fetch(`${BASE}/v1/sms/run/${runId}/delivery-status`, { headers });
const json = await res.json();
if (!res.ok) throw new Error(`${json.code}: ${json.message}`);
return json.data as { allDelivered: boolean; summary: { total: number; delivered: number; pending: number } };
}
```
---
Docs (login required): https://www.vibrate.co.il/docs/sms and https://www.vibrate.co.il/docs/whatsapp. Public copy of this skill: https://www.vibrate.co.il/vibrate-api-skill.md. Site index for AI: https://www.vibrate.co.il/llms.txt.
/v1/user/info/v1/sms/send/v1/sms/sendBulk/v1/sms/messages/v1/sms/run/{runId}/delivery-status/v1/sms/campaigns/v1/sms/campaigns/v1/sms/campaigns/{campaignId}/contacts/v1/sms/campaigns/{campaignId}/contacts/v1/sms/campaigns/{campaignId}/contacts/{contactId}/v1/sms/campaigns/{campaignId}/run/v1/whatsapp/template/send/v1/whatsapp/template/sendBulkמסמך Markdown אחד שמתאר את כל ה-REST API של Vibrate: אימות, כל endpoint של SMS ו-WhatsApp, מבנה הבקשות והתשובות, כללי מספרי טלפון, יחידות חיוב וקודי שגיאה. מדביקים אותו בעוזר AI כדי שיכתוב אינטגרציה נכונה בלי לנחש.
כל עוזר שמקבל טקסט: ChatGPT, Claude, Claude Code, Cursor, GitHub Copilot, Gemini ואחרים. ב-Claude Code וב-Cursor אפשר גם להתקין אותו כ-Skill או rule מקומי כך שייטען אוטומטית.
כן. פותחים חשבון חינם, טוענים יחידות SMS או מחברים מספר WhatsApp Business, ואז יוצרים מפתח גישה תחת הגדרות ← מפתחות גישה. המפתח נשלח בכותרת Authorization בכל בקשה.
לשלוח SMS בודד או בכמויות, להריץ קמפיינים מותאמים אישית לרשימות תפוצה, לנהל אנשי קשר, לבדוק סטטוס מסירה לכל הודעה, ולשלוח תבניות WhatsApp Business מאושרות עם משתנים ומדיה לנמען אחד או לרשימה שלמה.
כן. הוא נוצר מאותו מקור כמו תיעוד ה-API ומוגש מכתובת קבועה, כך שכל הורדה מחדש מחזירה את הגרסה העדכנית.
העתיקו פרומפט אחד ו-ChatGPT, Claude, Claude Code או Cursor יכירו את כל ה-API של Vibrate: שליחת SMS ותבניות WhatsApp, ניהול רשימות, סטטוס מסירה. API ל-SMS ו-WhatsApp Business בישראל.