# Mailing Lists API — Reference

Reference for third-party developers and LLM coding assistants integrating with the **mailing-list management** endpoint — the contact lists used by phone campaigns, email campaigns, IVR whitelists and broadcast tools.

For the full HTML reference (with diagrams and Hebrew explanations) see [mailingListsApiDocs.html](mailingListsApiDocs.html).

---

## Base URL

```
https://app.ipsales.co.il/mailingListsApi.php
```

All requests **MUST be sent over POST**. Parameters can be sent as `application/x-www-form-urlencoded`, `application/json`, or `multipart/form-data` (when uploading a file).

---

## Authentication

Every request must include an API key.

| Location              | Example                              |
|-----------------------|--------------------------------------|
| POST body (form)      | `apiKey=YOUR_API_KEY&...`            |
| POST body (JSON)      | `{ "apiKey": "YOUR_API_KEY", ... }`  |

The API key identifies the tenant account that owns the mailing list. Treat it like a password — never embed in browser code or public repos.

---

## Overview

A **mailing list** is a named collection of contacts. Each contact entry holds:

- `phone` — the primary phone number.
- `firstName`, `lastName` — display name (either or both optional).
- `email` — optional e-mail address.
- `status` — `0` = active, `1` = blocked. Blocked contacts are excluded from outgoing campaigns.

Mailing lists are addressed by their numeric **list ID** (`mailingList`).

You can:

- **Add / update / replace / delete** contacts in a list — `uplodePhones`.
- **List** the contacts in a list (with search and pagination) — `phonesList`.
- **Add or update a single contact** — `phoneEdit`.
- **Delete contacts** by ID — `phonesDelete`.
- **Block / unblock contacts** — `setStatus`.

> **Spelling note.** The action name `uplodePhones` is intentional and case-sensitive — it is preserved for backwards compatibility with existing integrations. Use it exactly as shown.

---

## Action — `uplodePhones`

Bulk import contacts into a mailing list. Supports four import modes: add-and-update, replace, insert-only, and delete.

### Request

`POST` to `https://app.ipsales.co.il/mailingListsApi.php`.

| Param         | Required | Type     | Description                                                                                  |
|---------------|----------|----------|----------------------------------------------------------------------------------------------|
| `action`      | yes      | string   | Must be `uplodePhones`.                                                                      |
| `apiKey`      | yes      | string   | Tenant API key.                                                                              |
| `mailingList` | yes      | integer  | Numeric ID of the target mailing list.                                                       |
| `phones`      | yes\*    | array / JSON-string | Array of contact rows (see [Contact row](#contact-row) below). \*Not required when `insertType=delete` is used to clear the entire list. |
| `insertType`  | no       | enum     | Import mode. Default `all`. See [Import modes](#import-modes).                               |
| `name`        | no       | string   | Reserved — display name for the import batch. May be omitted.                                |

#### Contact row

Each entry inside `phones` is an object:

| Field       | Required | Type    | Description                                                |
|-------------|----------|---------|------------------------------------------------------------|
| `phone`     | yes\*    | string  | Phone number. Will be normalized server-side.              |
| `firstName` | no       | string  | First name.                                                |
| `lastName`  | no       | string  | Last name.                                                 |
| `email`     | no       | string  | E-mail address. \*Either `phone` or `email` must be set.   |
| `status`    | no       | integer | `0` = active (default), `1` = blocked.                     |

#### Import modes

| `insertType`  | Behavior                                                                                                              |
|---------------|-----------------------------------------------------------------------------------------------------------------------|
| `all`         | (default) — Add new contacts and update fields of existing ones. Match by `phone`, then by `email`.                    |
| `replacing`   | Empty the list, then insert the new rows. **Destructive** — existing contacts in this list are removed.               |
| `insert`      | Insert only — new contacts are added; rows that already exist (by `phone` / `email`) are skipped silently.            |
| `delete`      | Remove the matching contacts from the list. Rows in `phones` that don't exist are ignored.                            |

### Successful response

HTTP 200, JSON:

```json
{
  "newNumbers":     12,
  "updateNumbers":  4,
  "errorNumbers":   1,
  "deletedNumbers": 0
}
```

| Field             | Description                                                       |
|-------------------|-------------------------------------------------------------------|
| `newNumbers`      | Number of contacts that were inserted.                            |
| `updateNumbers`   | Number of existing contacts that were updated.                    |
| `errorNumbers`    | Number of rows skipped because they had neither `phone` nor `email`. |
| `deletedNumbers`  | Number of contacts removed (relevant for `replacing` and `delete`).|

### Example — cURL (form, `phones` as JSON string)

```bash
curl -X POST https://app.ipsales.co.il/mailingListsApi.php \
  -d "action=uplodePhones" \
  -d "apiKey=YOUR_API_KEY" \
  -d "mailingList=1042" \
  -d "insertType=all" \
  --data-urlencode 'phones=[
    {"phone":"0501234567","firstName":"Avi","lastName":"Cohen","email":"avi@example.com","status":0},
    {"phone":"0507654321","firstName":"Dana","lastName":"Levy","email":"","status":0}
  ]'
```

### Example — PHP

```php
$payload = [
    'action'      => 'uplodePhones',
    'apiKey'      => 'YOUR_API_KEY',
    'mailingList' => 1042,
    'insertType'  => 'all',
    'phones'      => json_encode([
        ['phone' => '0501234567', 'firstName' => 'Avi',  'lastName' => 'Cohen', 'email' => 'avi@example.com',  'status' => 0],
        ['phone' => '0507654321', 'firstName' => 'Dana', 'lastName' => 'Levy',  'email' => '',                 'status' => 0],
    ]),
];

$ch = curl_init('https://app.ipsales.co.il/mailingListsApi.php');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payload));
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
```

### Example — Python (requests, JSON body)

```python
import requests

r = requests.post('https://app.ipsales.co.il/mailingListsApi.php', json={
    'action':      'uplodePhones',
    'apiKey':      'YOUR_API_KEY',
    'mailingList': 1042,
    'insertType':  'all',
    'phones': [
        {'phone': '0501234567', 'firstName': 'Avi',  'lastName': 'Cohen', 'email': 'avi@example.com', 'status': 0},
        {'phone': '0507654321', 'firstName': 'Dana', 'lastName': 'Levy',  'email': '',                'status': 0},
    ],
})
print(r.json())
```

---

## Action — `phonesList`

Read the contacts inside a mailing list. Supports free-text search and pagination.

### Request

| Param         | Required | Type    | Description                                                                |
|---------------|----------|---------|----------------------------------------------------------------------------|
| `action`      | yes      | string  | Must be `phonesList`.                                                      |
| `apiKey`      | yes      | string  | Tenant API key.                                                            |
| `mailingList` | yes      | integer | Numeric ID of the mailing list.                                            |
| `freeSerch`   | no       | string  | Free-text search across `phone`, `firstName`, `lastName`. (Spelling preserved for backwards compatibility.) |
| `limit`       | no       | integer | Page size. When omitted, all rows are returned without paging.             |
| `page`        | no       | integer | Zero-based page number. Used with `limit`.                                 |

### Successful response

```json
{
  "phonesList": {
    "10001": {
      "id":        "10001",
      "phone1":    "0501234567",
      "phone2":    "",
      "phone3":    "",
      "phones":    "0501234567",
      "firstName": "Avi",
      "lastName":  "Cohen",
      "email":     "avi@example.com",
      "email2":    "",
      "emails":    "avi@example.com",
      "status":    "0",
      "RHstatus":  0
    }
  },
  "phonesCount": "1,250",
  "fromLine":    0,
  "toLine":      50
}
```

| Field                    | Description                                                              |
|--------------------------|--------------------------------------------------------------------------|
| `phonesList`             | Object keyed by contact ID; each value is the contact row.               |
| `phonesList.<id>.id`     | Contact ID — pass this to `phonesDelete` or `phoneEdit` to address the row. |
| `phonesList.<id>.phones` | Comma-joined string of all phone numbers on the contact.                 |
| `phonesList.<id>.emails` | Comma-joined string of all e-mails on the contact.                       |
| `phonesList.<id>.status` | `"0"` active / `"1"` blocked.                                            |
| `phonesCount`            | Total contacts matching the filter, formatted with thousand-separators.  |
| `fromLine`, `toLine`     | First/last index of the returned page.                                   |

### Example

```bash
curl -X POST https://app.ipsales.co.il/mailingListsApi.php \
  -d "action=phonesList" \
  -d "apiKey=YOUR_API_KEY" \
  -d "mailingList=1042" \
  -d "freeSerch=Cohen" \
  -d "limit=50" \
  -d "page=0"
```

---

## Action — `phoneEdit`

Add or update a single contact.

### Request

| Param         | Required | Type             | Description                                                                  |
|---------------|----------|------------------|------------------------------------------------------------------------------|
| `action`      | yes      | string           | Must be `phoneEdit`.                                                         |
| `apiKey`      | yes      | string           | Tenant API key.                                                              |
| `mailingList` | yes      | integer          | Numeric ID of the mailing list.                                              |
| `id`          | no       | integer / string | Contact ID for update. Omit (or pass anything ≤ 0) to insert a new contact.  |
| `phone1`      | yes\*    | string           | Primary phone. \*Either `phone1` or `email` must be set.                     |
| `firstName`   | no       | string           | First name.                                                                  |
| `lastName`    | no       | string           | Last name.                                                                   |
| `email`       | yes\*    | string           | Primary e-mail. \*Either `phone1` or `email` must be set.                    |
| `email2`      | no       | string           | Secondary e-mail.                                                            |

When `id` is not provided, the server first searches the list by `phone1` or `email`. If a match is found, it is updated; otherwise a new contact is inserted.

### Successful response

```json
{ "status": "Ok", "note": "איש הקשר נשמר בהצלחה" }
```

### Error response

```json
{ "status": "Error", "note": "חייב טלפון ראשי או כתובת מייל" }
```

Returned when neither `phone1` nor `email` is supplied.

### Example

```bash
curl -X POST https://app.ipsales.co.il/mailingListsApi.php \
  -d "action=phoneEdit" \
  -d "apiKey=YOUR_API_KEY" \
  -d "mailingList=1042" \
  -d "phone1=0501234567" \
  -d "firstName=Avi" \
  -d "lastName=Cohen" \
  -d "email=avi@example.com"
```

---

## Action — `phonesDelete`

Delete one or more contacts by ID.

### Request

| Param         | Required | Type           | Description                                                              |
|---------------|----------|----------------|--------------------------------------------------------------------------|
| `action`      | yes      | string         | Must be `phonesDelete`.                                                  |
| `apiKey`      | yes      | string         | Tenant API key.                                                          |
| `mailingList` | yes      | integer        | Numeric ID of the mailing list.                                          |
| `deleteList`  | yes      | string / array | Comma-separated string of contact IDs, or a JSON array of IDs.           |

### Successful response

```json
{ "status": "Ok", "note": "המספרים נמחקו בהצלחה" }
```

### Example

```bash
curl -X POST https://app.ipsales.co.il/mailingListsApi.php \
  -d "action=phonesDelete" \
  -d "apiKey=YOUR_API_KEY" \
  -d "mailingList=1042" \
  -d "deleteList=10001,10002,10003"
```

---

## Action — `setStatus`

Block or unblock contacts. Blocked contacts (`status=1`) are excluded from outgoing campaigns until they are re-activated.

### Request

| Param         | Required | Type    | Description                                                                       |
|---------------|----------|---------|-----------------------------------------------------------------------------------|
| `action`      | yes      | string  | Must be `setStatus`.                                                              |
| `apiKey`      | yes      | string  | Tenant API key.                                                                   |
| `mailingList` | yes      | integer | Numeric ID of the mailing list.                                                   |
| `phone`       | yes      | string  | Single contact **ID**, or several IDs separated by commas (e.g. `10001,10002`). Despite the name, this parameter accepts contact IDs as returned by `phonesList`. |
| `status`      | yes      | integer | `1` = block, `0` = unblock.                                                       |

### Successful response

```json
{
  "status": "Ok",
  "note":   "המספר נחסם בהצלחה",
  "phones": ["10001", "10002"]
}
```

`note` is `המספר נחסם בהצלחה` when blocking and `המספר אושר בהצלחה` when unblocking.

### Example — block two contacts

```bash
curl -X POST https://app.ipsales.co.il/mailingListsApi.php \
  -d "action=setStatus" \
  -d "apiKey=YOUR_API_KEY" \
  -d "mailingList=1042" \
  -d "phone=10001,10002" \
  -d "status=1"
```

### Example — unblock a single contact

```bash
curl -X POST https://app.ipsales.co.il/mailingListsApi.php \
  -d "action=setStatus" \
  -d "apiKey=YOUR_API_KEY" \
  -d "mailingList=1042" \
  -d "phone=10001" \
  -d "status=0"
```

---

## Recipes

### 1. "Sync today's CRM segment to a campaign list"

Use `insertType=all`. New contacts are added, existing ones are updated by phone match.

```python
requests.post(URL, json={
    'action': 'uplodePhones', 'apiKey': KEY, 'mailingList': 1042,
    'insertType': 'all',
    'phones': [
        {'phone': c.phone, 'firstName': c.first, 'lastName': c.last,
         'email': c.email, 'status': 0}
        for c in todays_segment
    ],
})
```

### 2. "Replace the entire weekly broadcast list"

Use `insertType=replacing`. The list is emptied first, then refilled.

```python
requests.post(URL, json={
    'action': 'uplodePhones', 'apiKey': KEY, 'mailingList': 1042,
    'insertType': 'replacing',
    'phones': new_weekly_list,
})
```

### 3. "Process opt-outs"

For each phone that opted out, look up the contact ID via `phonesList`, then call `setStatus` with `status=1` to block:

```python
listing = requests.post(URL, data={'action':'phonesList', 'apiKey':KEY,
                                   'mailingList':1042, 'freeSerch':optout_phone}).json()
ids = ','.join(listing['phonesList'].keys())
requests.post(URL, data={'action':'setStatus', 'apiKey':KEY,
                         'mailingList':1042, 'phone':ids, 'status':1})
```

### 4. "Remove specific contacts entirely"

When you want the contacts gone (not blocked), use `phonesDelete` with the IDs from `phonesList`:

```python
requests.post(URL, data={'action':'phonesDelete', 'apiKey':KEY,
                         'mailingList':1042, 'deleteList':'10001,10002'})
```

---

## Implementation notes

- **Always check `status === "Ok"`** — the mailing-lists API returns `"Ok"` (mixed case) for success, distinct from some sister APIs that return `"OK"` (all-caps). Compare case-insensitively if you talk to several IP-Sales APIs from the same client.
- **Phone normalization.** Phone numbers are normalized server-side (digits only, leading-zero local format). You can send any human-readable form (`050-123-4567`, `+972-50-123-4567`) — the server will canonicalize.
- **Either phone or email is required** for every contact row. Rows with both empty are silently rejected and counted in `errorNumbers`.
- **Block vs. delete.** `setStatus` keeps the row but flags it as inactive — useful for compliant opt-out tracking. `phonesDelete` removes the row completely.
- **`setStatus` parameter naming.** The parameter is named `phone` for historical reasons but accepts **contact IDs** (the `id` field returned by `phonesList`), not phone-number strings. Send a comma-separated list of IDs to act on multiple contacts in one call.
- **Searching.** `freeSerch` (sic) is a free-text query matched against phone digits, first name, and last name. Send only digits to search by phone (`-` is stripped server-side).
- **Spelling preserved for compatibility.** `uplodePhones` and `freeSerch` are intentionally spelled this way and have been stable since launch — keep the misspellings exactly as shown.
