PHP (Guzzle) PHP (cURL) cURL JavaScript Python

Вступ

Це сторінка документації API KWIGA. За допомогою API ви можете виконувати дії від свого імені в ваших кабінетах KWIGA — кабінет це ваш робочий простір (акаунт / тенант), де живуть ваші курси, контакти та решта даних.

Для того щоб увімкнути API, в особистому кабінеті в розділі settings потрібно відмітити відповідний чекбокс. Після цього буде згенерований токен для API та отриманий хеш кабінету, які потрібні для подальших звернень до API.

При компрометації токена його можна перевипустити, що зробить минулий токен неактивним і згенерує новий.

API доступний тільки для тих користувачів, у кого в кабінеті включено API.

API має обмеження на кількість звернень 200 запитів на хвилину. Ліміт рахується окремо для кожного API-токена.

У кожній відповіді повертаються такі заголовки з інформацією про ліміт:

Заголовок Опис
X-RateLimit-Limit максимальна кількість запитів на хвилину.
X-RateLimit-Remaining скільки запитів ще доступно в поточній хвилині.
Retry-After через скільки секунд можна повторити запит. Повертається лише при перевищенні ліміту (HTTP 429).
X-RateLimit-Reset UNIX timestamp, коли скидається поточне вікно. Повертається лише при перевищенні ліміту (HTTP 429).

Базова робота з API

<?php
// Get contact by ID

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/contacts/{id}', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get contact by ID

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/{id}');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/contacts/{id}' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get contact by ID
const url = 'https://api.kwiga.com/contacts/{id}';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get contact by ID
import requests

url = 'https://api.kwiga.com/contacts/{id}'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Всі запити повинні надсилатися на домен:

https://api.kwiga.com

Для авторизації передаємо API-токен в одному з варіантів:

Для ідентифікації кабінету, в якому відбуваються дії, обов'язково передаємо хеш-кабінету в одному з варіантів:

PUT та DELETE запити можна надсилати POST-запитом із зазначенням додаткового параметра _method з потрібним методом (PUT або DELETE).

Встановити локалізацію довідників та повідомлень валідації можна заголовком:

X-Language: {locale}

Locale Description
en English (default)
cs Czech
de German
el Greek
es Spanish
fr Franch
hu Hungarian
it Italian
ka Georgian
lv Polish
pl Polish
pt Portuguese
ro Romanian
ru Russian
uk Ukrainian
zh Chinese (Simplified)

Помилки

Код помилки Значення
400 Bad Request - Ваш запит невірний.
401 Unauthorized - Ваш API-ключ невірний.
403 Forbidden - Запитаний ресурс захован та доступний лише адміністраторам.
404 Not Found - Не знайдено. Вказана сторінка не знайдена.
405 Method Not Allowed - Метод не дозволений. Серверу відомий метод запиту, але цільовий ресурс не підтримує цей метод.
422 Unprocessable entity - Сутність неможливо обробити.
429 Too Many Requests - Дуже багато запитів - Ви надсилаєте надто багато запитів, зупиніться!
500 Internal Server Error - Внутрішня помилка сервера. Проблема із нашим сервером. Повторіть спробу пізніше.
503 Service Unavailable - ми тимчасово відключені від мережі через технічне обслуговування. Повторіть спробу пізніше.

CRM. Контакти

Список контактів

Приклад запиту:

<?php
// Get contacts list

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/contacts', $options);

$result = json_decode($response->getBody());
?>


# ---
# Paginated example
# ---

<?php
// Get contacts list with pagination

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/contacts?page=1&per_page=15', $options);

$result = json_decode($response->getBody());
?>


# ---
# Filtered example
# ---

<?php
// Get contacts list with filters

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/contacts?page=1&per_page=15&filters[date_from]=2022-04-27&filters[search]=example.com&with_offers=1', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get contacts list

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>


# ---
# Paginated example
# ---

<?php
// Get contacts list with pagination

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts?page=1&per_page=15');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>


# ---
# Filtered example
# ---

<?php
// Get contacts list with filters

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts?page=1&per_page=15&filters[date_from]=2022-04-27&filters[search]=example.com&with_offers=1');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/contacts' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'


# ---
# Paginated example
# ---

curl --location --request GET 'https://api.kwiga.com/contacts?page=1&per_page=15' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'


# ---
# Filtered example
# ---

curl --location --request GET 'https://api.kwiga.com/contacts?page=1&per_page=15&filters[date_from]=2022-04-27&filters[search]=example.com&with_offers=1' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get contacts list
const url = 'https://api.kwiga.com/contacts';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });


# ---
# Paginated example
# ---

// Get contacts list with pagination
const url = 'https://api.kwiga.com/contacts?page=1&per_page=15';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });


# ---
# Filtered example
# ---

// Get contacts list with filters
const url = 'https://api.kwiga.com/contacts?page=1&per_page=15&filters[date_from]=2022-04-27&filters[search]=example.com&with_offers=1';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get contacts list
import requests

url = 'https://api.kwiga.com/contacts'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()


# ---
# Paginated example
# ---

# Get contacts list with pagination
import requests

url = 'https://api.kwiga.com/contacts?page=1&per_page=15'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()


# ---
# Filtered example
# ---

# Get contacts list with filters
import requests

url = 'https://api.kwiga.com/contacts?page=1&per_page=15&filters[date_from]=2022-04-27&filters[search]=example.com&with_offers=1'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
  "data": [
    {
      "id": 1,
      "created_at": "2022-02-04T12:17:32.000000Z",
      "email": "test@example.com",
      "first_name": "James",
      "last_name": "Bond",
      "phone": "+380931234567",
      "tags": [
          {
              "id": 93,
              "name": "test-tag"
          }
      ],
      "offers": [
          {
              "id": 8,
              "unique_offer_code": "ptJmPPXVYs0t",
              "title": "Предложение #8",
              "limit_type": {
                  "id": 1,
                  "name": "Неограничено"
              },
              "limit_of_sales": null
          }
      ]
    },
    "utm": {
        "utm_source": [
            "test-source"
        ],
        "utm_campaign": [],
        "utm_medium": [],
        "utm_term": [
            "test-term"
        ],
        "utm_content": []
    },
    {
      "id": 2,
      "created_at": "2022-02-04T12:17:32.000000Z",
      "email": "test2@example.com",
      "first_name": "Petr",
      "last_name": "Ivanov",
      "phone": "+380983234512",
      "tags": [],
      "offers": []
    }
  ],
  "links": {
        "first": "https://api.kwiga.com/contacts?page=1",
        "last": "https://api.kwiga.com/contacts?page=2",
        "prev": null,
        "next": "https://api.kwiga.com/contacts?page=2"
   },
   "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 2,
        "links": [
            {
                "url": null,
                "label": "&laquo; translation missing: ua.pagination_prev",
                "active": false
            },
            {
                "url": "https://api.kwiga.com/contacts?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": "https://api.kwiga.com/contacts?page=2",
                "label": "2",
                "active": false
            },
            {
                "url": "https://api.kwiga.com/contacts?page=2",
                "label": "translation missing: ua.pagination_next &raquo;",
                "active": false
            }
        ],
        "path": "https://api.kwiga.com/contacts",
        "per_page": 15,
        "to": 2,
        "total": 3
    }
}

GET https://api.kwiga.com/contacts

URL Parameters

filters object optional
Filter parameters
is_active integer optional
Фільтр активних контактів
date_from datetime optional
Фільтр за датою створення. Параметр 'від'
date_to datetime optional
Фільтр за датою створення. Параметр 'до'
last_activity_from datetime optional
Фільтр за датою останньої активності. Параметр 'від'
last_activity_to datetime optional
Фільтр за датою останньої активності. Параметр 'до'
search string optional
Фільтр по email, телефону, ПІБ
utm_source string optional
utm_source
utm_campaign string optional
utm_campaign
utm_medium string optional
utm_medium
utm_term string optional
utm_term
utm_content string optional
utm_content
offers integer[] optional
offers ids
products integer[] optional
products ids
emails string/string[] optional
Фільтр за точним email-адресою. Приймає рядок через кому або повторюваний масив; кожне значення має бути валідним email.
contact_ids integer/integer[] optional
Фільтр за id контактів. Приймає рядок через кому або повторюваний масив цілих чисел.
user_ids integer/integer[] optional
Фільтр за id юзерів (акаунтів учня). Приймає рядок через кому або повторюваний масив цілих чисел.

with_orders boolean optional
Додатково отримати інформацію по замовленням та пропозиціям контакта
with_certificates boolean optional
Додатково отримати інформацію по сертифікатам контакта
page integer optional
Номер сторінки
Default: 1
per_page integer optional
Кількість елементів вибірки
Default: 15
sort_by string optional
Possible values: asc, descDefault: desc

Структура відповіді

Елементи поточної сторінки.
Посилання на інші сторінки того самого списку.
Стан пагінації для поточного запиту (номер сторінки, загальна кількість тощо).

POST-аліас

POST https://api.kwiga.com/contacts/query

Функціональний аліас для GET-ендпоінта вище. Приймає ті самі параметри в тілі запиту замість query-string — стане в нагоді, коли список фільтрів завеликий для URL (або просто зручніше збирати JSON на клієнті). Body має пріоритет над query-string, форма відповіді ідентична.

Отримання контакту

Приклад запиту:

<?php
// Get contact by ID

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/contacts/{id}', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get contact by ID

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/{id}');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/contacts/{id}' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get contact by ID
const url = 'https://api.kwiga.com/contacts/{id}';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get contact by ID
import requests

url = 'https://api.kwiga.com/contacts/{id}'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
    "data": {
        "id": 132,
        "email": "bond@example.com",
        "first_name": "James",
        "last_name": "Bond",
        "phone_number": "931234567",
        "tags": [],
        "created_at": "2023-06-26T19:01:00.000000Z",
        "additional_fields": [
            {
                "id": 110,
                "field": {
                    "id": 17,
                    "title": "test global",
                    "is_local": false
                },
                "value": "this is test value"
            }
        ]
    }
}

GET https://api.kwiga.com/contacts/:contact

URL Parameters

with_certificates boolean optional
Додатково отримати інформацію по сертифікатам контакта

Структура відповіді

Створення контакту

Приклад запиту:

<?php
// Create new contact

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
    'json' => [
        'first_name' => 'James',
        'last_name' => 'Bond',
        'email' => 'bond@example.com',
        'send_activation_email' => true,
        'phone' => '+380931234567',
        'manager_ids' => [264, 288],
        'additional_fields' => [{"field_id"=>17, "value"=>"this is test value"}],
    ],
];

$response = $client->request('POST', '/contacts', $options);

$result = json_decode($response->getBody());
?>
<?php
// Create new contact

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

$data = [
    'first_name' => 'James',
    'last_name' => 'Bond',
    'email' => 'bond@example.com',
    'send_activation_email' => true,
    'phone' => '+380931234567',
    'manager_ids' => [264, 288],
    'additional_fields' => [{"field_id"=>17, "value"=>"this is test value"}],
];

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request POST 'https://api.kwiga.com/contacts' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"first_name":"James","last_name":"Bond","email":"bond@example.com","send_activation_email":true,"phone":"+380931234567","manager_ids":[264,288],"additional_fields":[{"field_id":17,"value":"this is test value"}]}'
// Create new contact
const url = 'https://api.kwiga.com/contacts';

const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
  body: JSON.stringify({
    'first_name': 'James',
    'last_name': 'Bond',
    'email': 'bond@example.com',
    'send_activation_email': true,
    'phone': '+380931234567',
    'manager_ids': [264, 288],
    'additional_fields': [{"field_id"=>17, "value"=>"this is test value"}]
  })
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Create new contact
import requests

url = 'https://api.kwiga.com/contacts'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

data = {
    'first_name': 'James',
    'last_name': 'Bond',
    'email': 'bond@example.com',
    'send_activation_email': true,
    'phone': '+380931234567',
    'manager_ids': [264, 288],
    'additional_fields': [{"field_id"=>17, "value"=>"this is test value"}],
}

response = requests.post(url, headers=headers, json=data)

result = response.json()

Приклад відповіді:

{
    "data": {
        "id": 132,
        "email": "bond@example.com",
        "first_name": "James",
        "last_name": "Bond",
        "phone_number": "931234567",
        "tags": [],
        "created_at": "2023-06-26T19:01:00.000000Z",
        "additional_fields": [
            {
                "id": 110,
                "field": {
                    "id": 17,
                    "title": "test global",
                    "is_local": false
                },
                "value": "this is test value"
            }
        ]
    }
}

POST https://api.kwiga.com/contacts

Request

email string required
Email - має бути унікальним у рамках кабінету
phone string optional
Номер телефону — формат: +{код країни}{телефон}
first_name string optional
Ім'я контакту
middle_name string optional
По-батькові контакту (або middle name)
last_name string optional
Прізвище контакту
name string optional
Повне ім'я одним рядком. Використовуйте, якщо у вас немає розбивки на ім'я/по-батькові/прізвище — сервер збереже значення як ім'я контакту.
tags string[] optional
Теги
send_activation_email boolean optional
Надіслати вітальний лист
locale string optional
Мова контакту в форматі iso_2. Повний список значень див. у блоці локалей, які підтримуються.
Default: en
create_order boolean optional
Створити пусте замовлення
order_stage_id integer optional
Ідентифікатор статусу замовлення у воронці (можна отримати на сторінці CRM → Замовлення → Налаштування → Список статусів)
additional_fields object[] optional
Поля користувача (кастомні поля)
field_id integer optional
id кастомного поля (можна отримати в CRM → Контакти → Налаштування → Додавання полів користувача)
value string optional
Значення кастомного поля

Структура відповіді

Додати покупку

Цей метод створює або знаходить контакт и додає йому покупку пропозиції

Приклад запиту:

<?php
// Add purchase to contact

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
    'json' => [
        'first_name' => 'James',
        'last_name' => 'Bond',
        'email' => 'bond@example.com',
        'send_activation_email' => true,
        'phone' => '+380931234567',
        'offer_id' => 18,
        'additional_fields' => [{"field_id"=>17, "value"=>"this is test value"}],
    ],
];

$response = $client->request('POST', '/contacts/purchases', $options);

$result = json_decode($response->getBody());
?>
<?php
// Add purchase to contact

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/purchases');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

$data = [
    'first_name' => 'James',
    'last_name' => 'Bond',
    'email' => 'bond@example.com',
    'send_activation_email' => true,
    'phone' => '+380931234567',
    'offer_id' => 18,
    'additional_fields' => [{"field_id"=>17, "value"=>"this is test value"}],
];

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request POST 'https://api.kwiga.com/contacts/purchases' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"first_name":"James","last_name":"Bond","email":"bond@example.com","send_activation_email":true,"phone":"+380931234567","offer_id":18,"additional_fields":[{"field_id":17,"value":"this is test value"}]}'
// Add purchase to contact
const url = 'https://api.kwiga.com/contacts/purchases';

const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
  body: JSON.stringify({
    'first_name': 'James',
    'last_name': 'Bond',
    'email': 'bond@example.com',
    'send_activation_email': true,
    'phone': '+380931234567',
    'offer_id': 18,
    'additional_fields': [{"field_id"=>17, "value"=>"this is test value"}]
  })
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Add purchase to contact
import requests

url = 'https://api.kwiga.com/contacts/purchases'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

data = {
    'first_name': 'James',
    'last_name': 'Bond',
    'email': 'bond@example.com',
    'send_activation_email': true,
    'phone': '+380931234567',
    'offer_id': 18,
    'additional_fields': [{"field_id"=>17, "value"=>"this is test value"}],
}

response = requests.post(url, headers=headers, json=data)

result = response.json()

Приклад відповіді:

{
    "data": {
        "id": 132,
        "email": "bond@example.com",
        "first_name": "James",
        "last_name": "Bond",
        "phone_number": "931234567",
        "tags": [],
        "created_at": "2023-06-26T19:01:00.000000Z",
        "additional_fields": [
            {
                "id": 110,
                "field": {
                    "id": 17,
                    "title": "test global",
                    "is_local": false
                },
                "value": "this is test value"
            }
        ],
        "orders": [
            {
                "id": 1060,
                "type_id": 1,
                "first_paid_at": "2023-10-13T18:04:02.000000Z",
                "paid_at": "2023-10-13T18:04:02.000000Z",
                "created_at": "2023-10-13T18:04:02.000000Z",
                "updated_at": "2023-10-13T18:04:02.000000Z",
                "products": [
                    {
                        "id": 25,
                        "productable_id": 10,
                        "productable_type": "course",
                        "title": "test course",
                        "link": "https://sample-school.kwiga.com/courses/test-course"
                    }
                ],
                "payments": [
                    {
                        "id": 1231,
                        "status": 2,
                        "status_title": "Paid",
                        "payment_type": null,
                        "payment_type_title": null,
                        "payment_form": null,
                        "payment_form_title": null,
                        "price_info": {
                            "amount": 0,
                            "currency": {
                                "id": 147,
                                "code": "UAH",
                                "html_code": "₴",
                                "html_letter_code": "грн"
                            }
                        },
                        "paid_at": "2023-10-13T18:04:02.000000Z",
                        "created_at": "2023-10-13T18:04:02.000000Z",
                        "updated_at": "2023-10-13T18:04:02.000000Z",
                        "transactions": [
                            {
                                "id": 28,
                                "merchant_id": 2,
                                "payment_id": 1231,
                                "order_id": 1060,
                                "payment_system_status": "Declined",
                                "failure_reason": "Cardholder session expired",
                                "price": "147",
                                "currency_code": "UAH",
                                "payer_account": null,
                                "card_mask": null,
                                "rrn": null,
                                "fee": null,
                                "created_at": "2023-11-03T08:45:10.000000Z"
                            },
                            {
                                "id": 29,
                                "merchant_id": 2,
                                "payment_id": 1231,
                                "order_id": 1060,
                                "payment_system_status": "Approved",
                                "failure_reason": null,
                                "price": "147",
                                "currency_code": "UAH",
                                "payer_account": "JKNNASWTZ99SJ",
                                "card_mask": "53****2144",
                                "rrn": 330710335365,
                                "fee": null,
                                "created_at": "2023-11-03T08:48:10.000000Z"
                            }
                        ]
                    }
                ],
                "paid_status": "paid",
                "paid_status_title": "Сплачено",
                "order_stage": {
                    "id": 43,
                    "title": "Стейдж 1",
                    "order_group": {
                        "id": 22,
                        "slug": "voronka-1",
                        "title": null,
                        "order": 4,
                        "created_at": "2023-06-22T18:20:53.000000Z"
                    },
                    "order_funnel": {
                        "id": 1,
                        "title": "Воронка за замовчуванням",
                        "created_at": "2023-05-26T09:47:16.000000Z"
                    },
                    "created_at": "2023-06-22T18:21:10.000000Z"
                },
                "cost_info": {
                    "amount": 0,
                    "currency": {
                        "id": 147,
                        "code": "UAH",
                        "html_code": "₴",
                        "html_letter_code": "грн"
                    }
                },
                "managers": [
                    {
                        "id": 264,
                        "name": "test",
                        "email": "testfsdf@fdafasd.fsd"
                    },
                    {
                        "id": 288,
                        "name": "fdsf",
                        "email": "sdfs@fdf.dfss"
                    }
                ]
            }
        ]
    }
}

POST https://api.kwiga.com/contacts/purchases

Request

email string required
Email - має бути унікальним у рамках кабінету
phone string optional
Номер телефону — формат: +{код країни}{телефон}
first_name string optional
Ім'я контакту
middle_name string optional
По-батькові контакту (або middle name)
last_name string optional
Прізвище контакту
name string optional
Повне ім'я одним рядком. Використовуйте, якщо у вас немає розбивки на ім'я/по-батькові/прізвище — сервер збереже значення як ім'я контакту.
tags string[] optional
Теги
send_activation_email boolean optional
Надіслати вітальний лист
send_product_access_email boolean optional
Надіслати лист про доступ до продукту
send_payment_success_email boolean optional
Надіслати лист про успішну оплату пропозиції
locale string optional
Мова контакту в форматі iso_2. Повний список значень див. у блоці локалей, які підтримуються.
Default: en
offer_id integer optional
Ідентифікатор пропозиції — береться з кінця посилання сторінки редагування пропозиції (наприклад, https://sample-school.kwiga.com/expert/payments/offers/edit/3858). Якщо не переданий — запит звертається до поля product_ids.
product_ids integer[] optional
Масив id продуктів.
Якщо offer_id і product_ids відсутні, то буде створено пусте замовлення
order_stage_id integer optional
Ідентифікатор статусу замовлення у воронці (можна отримати на сторінці CRM → Замовлення → Налаштування → Список статусів)
is_paid boolean optional
Позначає створене замовлення як сплачене.
Default: true
manager_ids integer[] optional
Менеджери замовлення (можна отримати на сторінці Налаштування → Доступи по управлінню)
comment string optional
Коментар до замовлення. Max: 5000
Max length: 5000 characters
additional_fields object[] optional
Поля користувача (кастомні поля)
field_id integer optional
id кастомного поля (можна отримати в CRM → Контакти → Налаштування → Додавання полів користувача)
value string optional
Значення кастомного поля

Структура відповіді

Оновлення контакту

Приклад запиту:

<?php
// Update contact

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
    'json' => [
        'first_name' => 'John',
        'last_name' => 'Black',
        'email' => 'bond123@example.com',
        'phone' => '+380931112233',
        'tags' => ["test-tag"],
    ],
];

$response = $client->request('PUT', '/contacts/{id}', $options);

$result = json_decode($response->getBody());
?>
<?php
// Update contact

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/{id}');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');

$data = [
    'first_name' => 'John',
    'last_name' => 'Black',
    'email' => 'bond123@example.com',
    'phone' => '+380931112233',
    'tags' => ["test-tag"],
];

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request PUT 'https://api.kwiga.com/contacts/{id}' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"first_name":"John","last_name":"Black","email":"bond123@example.com","phone":"+380931112233","tags":["test-tag"]}'
// Update contact
const url = 'https://api.kwiga.com/contacts/{id}';

const options = {
  method: 'PUT',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
  body: JSON.stringify({
    'first_name': 'John',
    'last_name': 'Black',
    'email': 'bond123@example.com',
    'phone': '+380931112233',
    'tags': ["test-tag"]
  })
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Update contact
import requests

url = 'https://api.kwiga.com/contacts/{id}'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

data = {
    'first_name': 'John',
    'last_name': 'Black',
    'email': 'bond123@example.com',
    'phone': '+380931112233',
    'tags': ["test-tag"],
}

response = requests.put(url, headers=headers, json=data)

result = response.json()

Приклад відповіді:

{
    "data": {
        "id": 132,
        "email": "bond@example.com",
        "first_name": "James",
        "last_name": "Bond",
        "phone_number": "931234567",
        "tags": [],
        "created_at": "2023-06-26T19:01:00.000000Z",
        "additional_fields": [
            {
                "id": 110,
                "field": {
                    "id": 17,
                    "title": "test global",
                    "is_local": false
                },
                "value": "this is test value"
            }
        ]
    }
}

PUT https://api.kwiga.com/contacts/:contact

Request

email string optional
Email - має бути унікальним у рамках кабінету
phone string optional
Номер телефону — формат: +{код країни}{телефон}
first_name string optional
Ім'я контакту
last_name string optional
Прізвище контакту
tags string[] optional
Теги. Працюють в режимі sync. Тобто на контакті будуть тільки ті теги, які будуть передані
additional_fields object[] optional
Поля користувача (кастомні поля)
field_id integer optional
id кастомного поля (можна отримати в CRM → Контакти → Налаштування → Додавання полів користувача)
value string optional
Значення кастомного поля

Структура відповіді

Додавання тегів контактам

Приклад запиту:

<?php
// Add tags to contacts

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
    'json' => [
        'contacts' => [23698],
        'tags' => ["test-tag"],
    ],
];

$response = $client->request('POST', '/contacts/tags', $options);

$result = json_decode($response->getBody());
?>
<?php
// Add tags to contacts

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/tags');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

$data = [
    'contacts' => [23698],
    'tags' => ["test-tag"],
];

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request POST 'https://api.kwiga.com/contacts/tags' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"contacts":[23698],"tags":["test-tag"]}'
// Add tags to contacts
const url = 'https://api.kwiga.com/contacts/tags';

const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
  body: JSON.stringify({
    'contacts': [23698],
    'tags': ["test-tag"]
  })
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Add tags to contacts
import requests

url = 'https://api.kwiga.com/contacts/tags'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

data = {
    'contacts': [23698],
    'tags': ["test-tag"],
}

response = requests.post(url, headers=headers, json=data)

result = response.json()

Приклад відповіді:

{
    "success": true
}

POST https://api.kwiga.com/contacts/tags

Request

contact_ids integer/integer[] optional
Фільтр за id контактів. Приймає рядок через кому або повторюваний масив цілих чисел.
contacts integer[] optional
Legacy-аліас для contact_ids. Збережений заради зворотної сумісності; у нових інтеграціях використовуйте contact_ids.
tags string[] required
Теги

Структура відповіді

Тіло відповіді повертається без обгортки.

Видалення тегів контактів

Приклад запиту:

<?php
// Remove tags from contacts

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
    'json' => [
        'contacts' => [23698],
        'tags' => ["test-tag"],
    ],
];

$response = $client->request('DELETE', '/contacts/tags', $options);

$result = json_decode($response->getBody());
?>
<?php
// Remove tags from contacts

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/tags');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');

$data = [
    'contacts' => [23698],
    'tags' => ["test-tag"],
];

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request DELETE 'https://api.kwiga.com/contacts/tags' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"contacts":[23698],"tags":["test-tag"]}'
// Remove tags from contacts
const url = 'https://api.kwiga.com/contacts/tags';

const options = {
  method: 'DELETE',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
  body: JSON.stringify({
    'contacts': [23698],
    'tags': ["test-tag"]
  })
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Remove tags from contacts
import requests

url = 'https://api.kwiga.com/contacts/tags'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

data = {
    'contacts': [23698],
    'tags': ["test-tag"],
}

response = requests.delete(url, headers=headers, json=data)

result = response.json()

Приклад відповіді:

{
    "success": true
}

DELETE https://api.kwiga.com/contacts/tags

Request

contact_ids integer/integer[] optional
Фільтр за id контактів. Приймає рядок через кому або повторюваний масив цілих чисел.
contacts integer[] optional
Legacy-аліас для contact_ids. Збережений заради зворотної сумісності; у нових інтеграціях використовуйте contact_ids.
tags string[] required
Теги

Структура відповіді

Тіло відповіді повертається без обгортки.

Список продуктів контакту

Приклад запиту:

<?php
// Get contact products

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/contacts/:contact/products', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get contact products

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/:contact/products');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/contacts/:contact/products' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get contact products
const url = 'https://api.kwiga.com/contacts/:contact/products';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get contact products
import requests

url = 'https://api.kwiga.com/contacts/:contact/products'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
  "data": [
    {
      "id": 299,
      "productable_id": 142,
      "productable_type": "course",
      "title": "Copy Test backup",
      "image_url": "",
      "is_published": false,
      "aggregated_subscription": {
        "is_active": true,
        "is_paid": true,
        "start_at": "2025-05-05T15:09:04.000000Z",
        "end_at": null,
        "offer_end_at": null,
        "order_end_at": null,
        "count_available_days": 39,
        "count_left_days": null,
        "state": {
          "id": 2,
          "name": "Open",
          "title": "Open"
        }
      },
      "subscriptions": [
        {
          "id": 4775,
          "creator_id": 24457,
          "user_id": 24457,
          "product_id": 299,
          "order_id": 2710,
          "offer_id": 757,
          "is_active": true,
          "start_at": "2025-05-05T15:09:04.000000Z",
          "order_end_at": null,
          "end_at": null,
          "paid_at": "2025-05-05T15:09:04.000000Z",
          "created_at": "2025-05-05T15:09:04.000000Z",
          "updated_at": "2025-05-05T15:09:04.000000Z"
        }
      ]
    }
  ]
}

GET https://api.kwiga.com/contacts/:contact/products

Повертає список продуктів контакту з інформацією про підписки та терміни доступу. Параметр aggregated_subscription містить зведену інформацію про терміни та активність доступу на основі всіх підписок користувача по продукту. Параметр subscriptions містить масив всіх підписок користувача по продукту.

Структура відповіді

Елементи поточної сторінки.
Посилання на інші сторінки того самого списку.
Стан пагінації для поточного запиту (номер сторінки, загальна кількість тощо).

Видалити продукт у контакта

Приклад запиту:

<?php
// Delete contact product

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('DELETE', '/contacts/:contact/products/:product', $options);

$result = json_decode($response->getBody());
?>
<?php
// Delete contact product

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/:contact/products/:product');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request DELETE 'https://api.kwiga.com/contacts/:contact/products/:product' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Delete contact product
const url = 'https://api.kwiga.com/contacts/:contact/products/:product';

const options = {
  method: 'DELETE',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Delete contact product
import requests

url = 'https://api.kwiga.com/contacts/:contact/products/:product'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.delete(url, headers=headers)

result = response.json()

Приклад відповіді:

{
  "success": true
}

DELETE https://api.kwiga.com/contacts/:contact/products/:product

Видаляє підписки контакту по заданому продукту. Замовлення стають кастомними без доступу до видалених продуктів.

Структура відповіді

Тіло відповіді повертається без обгортки.

Видалити продукти у контакта (масово)

Приклад запиту:

<?php
// Delete contact products in bulk

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
    'json' => [
        'email' => 'user@example.com',
        'product_id' => 299,
        'offers' => [421],
    ],
];

$response = $client->request('DELETE', '/contacts/products', $options);

$result = json_decode($response->getBody());
?>
<?php
// Delete contact products in bulk

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/products');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');

$data = [
    'email' => 'user@example.com',
    'product_id' => 299,
    'offers' => [421],
];

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request DELETE 'https://api.kwiga.com/contacts/products' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"email":"user@example.com","product_id":299,"offers":[421]}'
// Delete contact products in bulk
const url = 'https://api.kwiga.com/contacts/products';

const options = {
  method: 'DELETE',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
  body: JSON.stringify({
    'email': 'user@example.com',
    'product_id': 299,
    'offers': [421]
  })
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Delete contact products in bulk
import requests

url = 'https://api.kwiga.com/contacts/products'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

data = {
    'email': 'user@example.com',
    'product_id': 299,
    'offers': [421],
}

response = requests.delete(url, headers=headers, json=data)

result = response.json()

Приклад відповіді:

{
  "data": {
    "affected_subscriptions": [
      2309,
      2661
    ],
    "affected_orders": [
      1578,
      1784
    ],
    "affected_by_offers": {
      "421": {
        "affected_subscriptions": [
          2309,
          2661
        ],
        "affected_orders": [
          1578,
          1784
        ]
      }
    },
    "affected_by_products": []
  },
  "contact_id": 125
}

DELETE https://api.kwiga.com/contacts/products

Видаляє підписки за заданими умовами, а замовлення стають кастомними без доступу до видалених продуктів. Можна комбінувати параметри product_id та offers для видалення частини продуктів по певному офферу.

Parameters

email string optional
Email контакту. Обов'язковий якщо contact_id не вказаний
contact_id integer optional
Id контакту. Обов'язковий якщо email не вказаний
product_id integer optional
Id продукту. Обов'язковий якщо offers не вказаний. Можна отримати наприклад в ендпоінті Список продуктів контакту або в Списку курсів (це буде поле product_id в курсі)
offers integer[] optional
Масив з id пропозицій по яких видаляємо підписки. Обов'язковий якщо product_id не вказаний. Можна отримати в адресному рядку редагування пропозиції або в апі в списку пропозицій контакту.

Структура відповіді

Вміст відповіді.
contact_id integer
ID of the contact whose subscriptions were affected

Продукти

Список продуктів кабінету

Приклад запиту:

<?php
// Get products list

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/products', $options);

$result = json_decode($response->getBody());
?>


# ---
# Paginated example
# ---

<?php
// Get products list with pagination and sorting

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/products?per_page=20&page=1&sort_by=asc', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get products list

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/products');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>


# ---
# Paginated example
# ---

<?php
// Get products list with pagination and sorting

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/products?per_page=20&page=1&sort_by=asc');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/products' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'


# ---
# Paginated example
# ---

curl --location --request GET 'https://api.kwiga.com/products?per_page=20&page=1&sort_by=asc' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get products list
const url = 'https://api.kwiga.com/products';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });


# ---
# Paginated example
# ---

// Get products list with pagination and sorting
const url = 'https://api.kwiga.com/products?per_page=20&page=1&sort_by=asc';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get products list
import requests

url = 'https://api.kwiga.com/products'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()


# ---
# Paginated example
# ---

# Get products list with pagination and sorting
import requests

url = 'https://api.kwiga.com/products?per_page=20&page=1&sort_by=asc'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
  "data": [
    {
      "id": 299,
      "productable_id": 142,
      "productable_type": "course",
      "title": "Sample Course Title",
      "link": "http://test.local/courses/test-slug"
    }
  ],
  "links": {
    "first": "https://api.kwiga.com/products?page=1",
    "last": "https://api.kwiga.com/products?page=5",
    "prev": null,
    "next": "https://api.kwiga.com/products?page=2"
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 5,
    "path": "https://api.kwiga.com/products",
    "per_page": 15,
    "to": 15,
    "total": 75
  }
}

GET https://api.kwiga.com/products

Список продуктів кабінету. Є пагінація, за замовчуванням 15.

URL Parameters

sort_by string optional
Possible values: asc, descDefault: desc
per_page integer optional
Кількість елементів на сторінці
Default: 15
page integer optional
Номер сторінки
Default: 1

Структура відповіді

Елементи поточної сторінки.
Посилання на інші сторінки того самого списку.
Стан пагінації для поточного запиту (номер сторінки, загальна кількість тощо).

Курси

Список курсів кабінету

Приклад запиту:

<?php
// Get courses list

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/courses', $options);

$result = json_decode($response->getBody());
?>


# ---
# With_params example
# ---

<?php
// Get courses list with pagination and includes

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/courses?with[]=offers&with[]=description&with[]=program&per_page=15&page=1', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get courses list

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/courses');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>


# ---
# With_params example
# ---

<?php
// Get courses list with pagination and includes

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/courses?with[]=offers&with[]=description&with[]=program&per_page=15&page=1');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/courses' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'


# ---
# With_params example
# ---

curl --location --request GET 'https://api.kwiga.com/courses?with[]=offers&with[]=description&with[]=program&per_page=15&page=1' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get courses list
const url = 'https://api.kwiga.com/courses';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });


# ---
# With_params example
# ---

// Get courses list with pagination and includes
const url = 'https://api.kwiga.com/courses?with[]=offers&with[]=description&with[]=program&per_page=15&page=1';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get courses list
import requests

url = 'https://api.kwiga.com/courses'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()


# ---
# With_params example
# ---

# Get courses list with pagination and includes
import requests

url = 'https://api.kwiga.com/courses?with[]=offers&with[]=description&with[]=program&per_page=15&page=1'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
  "data": [
    {
      "id": 226,
      "product_id": 431,
      "type": {
        "id": 1,
        "name": "Course",
        "type": "course"
      },
      "title": "Test черновик квизов",
      "slug": "test-chernovik-kvizov",
      "preview": {
        "id": 3140,
        "uuid": "bdfe1347-574f-4829-a745-09ba2176cc2a",
        "name": "image_13.jpeg",
        "original_name": "image_13.jpeg",
        "url": "https://cdn57098163.ahacdn.me/local/cabinet-1/rcIJuNkWmpCQ/image_13.jpeg",
        "thumbnails": {
          "xs": "https://cdn57098163.ahacdn.me/local/cabinet-1/rcIJuNkWmpCQ/image_13_thumb_150.jpeg",
          "small": "https://cdn57098163.ahacdn.me/local/cabinet-1/rcIJuNkWmpCQ/image_13_thumb_500.jpeg",
          "medium": "https://cdn57098163.ahacdn.me/local/cabinet-1/rcIJuNkWmpCQ/image_13.jpeg",
          "large": "https://cdn57098163.ahacdn.me/local/cabinet-1/rcIJuNkWmpCQ/image_13.jpeg",
          "default": "https://cdn57098163.ahacdn.me/local/cabinet-1/rcIJuNkWmpCQ/image_13.jpeg"
        },
        "extension": "jpeg",
        "type_id": 2,
        "mime_type": "image/jpeg"
      },
      "link": "http://test.local/courses/test-chernovik-kvizov",
      "status": {
        "id": 3,
        "name": "Published"
      }
    }
  ],
  "links": {
    "first": "http://api.kwiga.local/courses?page=1",
    "last": "http://api.kwiga.local/courses?page=1",
    "prev": null,
    "next": null
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 1,
    "links": [
      {
        "url": null,
        "label": "&laquo; Previous",
        "active": false
      },
      {
        "url": "http://api.kwiga.local/courses?page=1",
        "label": "1",
        "active": true
      },
      {
        "url": null,
        "label": "Next &raquo;",
        "active": false
      }
    ],
    "path": "http://api.kwiga.local/courses",
    "per_page": 15,
    "to": 1,
    "total": 1
  }
}

GET https://api.kwiga.com/courses

Список курсів кабінету. Є пагінація, за замовчуванням 15 (max: 15).

URL Parameters

with string[] optional
Масив з додатковими параметрами, які потрібно отримати разом з курсом. Можливі варіанти: offers (список всіх офферів з курсом), description (інфоблоки з описом курсу), program (дерево програми курсу)
Possible values: offers, description, program
sort_by string optional
Possible values: asc, descDefault: desc
per_page integer optional
Кількість елементів на сторінці
Maximum: 15Default: 15
page integer optional
Номер сторінки
Default: 1

Структура відповіді

Елементи поточної сторінки.
Посилання на інші сторінки того самого списку.
Стан пагінації для поточного запиту (номер сторінки, загальна кількість тощо).

Список учасників курсу

Приклад запиту:

<?php
// Get course users

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/courses/:course/users', $options);

$result = json_decode($response->getBody());
?>


# ---
# Filtered example
# ---

<?php
// Get course users with filters

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/courses/:course/users?progress_general_from=50&progress_general_to=100&per_page=20', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get course users

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/courses/:course/users');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>


# ---
# Filtered example
# ---

<?php
// Get course users with filters

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/courses/:course/users?progress_general_from=50&progress_general_to=100&per_page=20');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/courses/:course/users' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'


# ---
# Filtered example
# ---

curl --location --request GET 'https://api.kwiga.com/courses/:course/users?progress_general_from=50&progress_general_to=100&per_page=20' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get course users
const url = 'https://api.kwiga.com/courses/:course/users';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });


# ---
# Filtered example
# ---

// Get course users with filters
const url = 'https://api.kwiga.com/courses/:course/users?progress_general_from=50&progress_general_to=100&per_page=20';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get course users
import requests

url = 'https://api.kwiga.com/courses/:course/users'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()


# ---
# Filtered example
# ---

# Get course users with filters
import requests

url = 'https://api.kwiga.com/courses/:course/users?progress_general_from=50&progress_general_to=100&per_page=20'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
    "data": [
        {
            "user": {
                "id": 3,
                "name": "Admin Кабинет",
                "email": "test@test.com"
            },
            "contact": {
                "id": 1,
                "user_id": 3,
                "email": "test@test.com",
                "first_name": "test",
                "last_name": "admin cabinet",
                "phone": "979",
                "created_at": "2023-05-26T09:47:20.000000Z",
                "last_activity_at": null
            },
            "course_points": 0,
            "course_progress": {
                "course_id": 20,
                "course_url": "http://test.local/courses/Pm8CEofJ",
                "title": "Dripping",
                "lessons_count": 9,
                "lessons_count_viewed": 0,
                "lessons_viewed_percentage": 0,
                "lessons_count_completed": 0,
                "lessons_completion_percentage": 0,
                "quizzes_count": 0,
                "quizzes_count_completed": 0,
                "quizzes_completion_percentage": 0,
                "scores_max": 0,
                "quizzes_scores": 0,
                "product_scores": 0,
                "scores": 0,
                "is_completed": false,
                "completed_at": null,
                "current_lesson": {
                    "id": 48,
                    "course_id": 20,
                    "type_id": 1,
                    "status_id": 4,
                    "number": 6,
                    "title": "2",
                    "slug": "2",
                    "link": "http://test.local/courses/Pm8CEofJ/2",
                    "quizzes": [],
                    "module": {
                        "id": 7,
                        "course_id": 20,
                        "number": 1,
                        "title": "Module title"
                    }
                },
                "next_lesson": {
                    "id": 46,
                    "course_id": 20,
                    "type_id": 1,
                    "status_id": 4,
                    "number": 1,
                    "title": "3",
                    "slug": "3",
                    "link": "http://test.local/courses/Pm8CEofJ/3",
                    "module": {
                        "id": 7,
                        "course_id": 20,
                        "number": 1,
                        "title": "Module title"
                    }
                },
                "last_active_at": null,
                "is_checkpoints_skipped": false,
                "checkpoints": [],
                "is_current_dripping_date_skipped": false,
                "is_next_dripping_date_skipped": false,
                "current_dripping_date": null,
                "next_dripping_date": null
            },
            "lessons_available_count": 9,
            "is_full_access": true,
            "subscription": {
                "is_active": true,
                "is_paid": true,
                "start_at": "2024-04-23T13:45:02.000000Z",
                "end_at": null,
                "offer_end_at": null,
                "order_end_at": null,
                "count_available_days": 661,
                "count_left_days": null,
                "state": {
                    "id": 2,
                    "name": "Open",
                    "title": "Open"
                }
            }
        }
    ],
    "links": {
        "first": "http://api.kwiga.local/courses/20/users?page=1",
        "last": "http://api.kwiga.local/courses/20/users?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "active": false
            },
            {
                "url": "http://api.kwiga.local/courses/20/users?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "active": false
            }
        ],
        "path": "http://api.kwiga.local/courses/20/users",
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}

GET https://api.kwiga.com/courses/:course/users

Виводить список учасників курсу та їх прогрес. Є пагінація, за замовчуванням 15 (max: 250). Замініть :course на id курсу, який можна взяти в адресному рядку редагування/управління курсу або в ендпоінті по списку курсів.

URL Parameters

search string optional
Нестрогий пошук по імейлу або імені
contact_id integer optional
По id контакту
contact_ids integer/integer[] optional
Фільтр за id контактів. Приймає рядок через кому або повторюваний масив цілих чисел.
user_id integer optional
По id користувача
user_ids integer/integer[] optional
Фільтр за id юзерів (акаунтів учня). Приймає рядок через кому або повторюваний масив цілих чисел.
emails string/string[] optional
Фільтр за точним email-адресою. Приймає рядок через кому або повторюваний масив; кожне значення має бути валідним email.
progress_general_from integer optional
Загальний прогрес від (від 0 до 99)
progress_general_to integer optional
Загальний прогрес до (від 0 до 100)
lessons_viewed_from integer optional
Відсоток перегляду уроку від (від 0 до 99)
lessons_viewed_to integer optional
Відсоток перегляду уроку до (від 0 до 100)
quizzes_progress_from integer optional
Відсоток пройдених практик від (від 0 до 99)
quizzes_progress_to integer optional
Відсоток пройдених практик до (від 0 до 100)
last_activity_from datetime optional
Остання активність на курсі від (дата UTC)
last_activity_to datetime optional
Остання активність на курсі до (дата UTC)
per_page integer optional
Кількість елементів на сторінці
Maximum: 250Default: 15
page integer optional
Номер сторінки
Default: 1
include string/string[] optional

Необов'язковий список розширень відповіді через кому. Кожен токен підключає одну секцію відповіді — клієнт платить лише за те, що попросив.

  • course_program — додає програму курсу на верхньому рівні відповіді у поле course_program (масив вузлів CourseProgram; у lesson-вузлів у children ідуть CourseProgramSection з прив'язаними квізами). Повертається один раз поряд з data/links/meta, бо програма однакова для всіх учнів сторінки.
  • lesson_progress — додає у кожен елемент data[] поле lesson_progress: масив об'єктів LessonProgress (по одному запису на урок, по якому в учня є прогрес).
  • module_progress — додає у кожен елемент data[] поле module_progress: масив об'єктів ModuleProgress.
  • quiz_progress — додає у кожен елемент data[] поле quiz_progress: масив об'єктів QuizProgress, по одному запису на пару (course_lesson_id, quiz_id) зі зведенням за останньою non-cancelled спробою учня.

Увага: один і той самий квіз може бути прив'язаний до кількох уроків одного курсу, тому quiz_progress адресується парою урок/квіз, а не одним quiz_id. Клієнт зшиває per-user прогрес з деревом за course_nodeble_id lesson/module-вузлів і за парою (lesson.course_nodeble_id, quizzes[i].id) для section-вузлів.

Структура відповіді

Елементи поточної сторінки.
Посилання на інші сторінки того самого списку.
Стан пагінації для поточного запиту (номер сторінки, загальна кількість тощо).
Conditional: Returned when include contains course_program.
Програма курсу, повертається на верхньому рівні коли `include` містить `course_program`. Форма полів та сама, що в існуючій схемі `CourseProgram`, у lesson-вузлів у `children` лежать `CourseProgramSection`. Однакова для всіх учнів сторінки, тому API повертає її один раз замість повторення в кожному ряду.

POST-аліас

POST https://api.kwiga.com/courses/:course/users/query

Функціональний аліас для GET-ендпоінта вище. Приймає ті самі параметри в тілі запиту замість query-string — стане в нагоді, коли список фільтрів завеликий для URL (або просто зручніше збирати JSON на клієнті). Body має пріоритет над query-string, форма відповіді ідентична.

Отримання детальної аналітики по уроках

На додачу до зведення прогресу по курсу ендпоінт може повернути детальну розбивку прогресу по уроках. Розширення запитується query-параметром include (повний список токенів і тип даних, який кожен з них підключає, описаний у його описі вище, в URL Parameters). Програма курсу повертається один раз на верхньому рівні у полі course_program — вона однакова для всіх учнів сторінки, тому розмір відповіді залишається пропорційним добутку учнів на уроки/квізи, а не на розмір усього дерева.

Приклад відповіді з ?include=course_program,lesson_progress,module_progress,quiz_progress

{
    "data": [
        {
            "user": {
                "id": 3,
                "name": "Admin Кабинет",
                "email": "test@test.com"
            },
            "contact": {
                "id": 1,
                "user_id": 3,
                "email": "test@test.com",
                "first_name": "test",
                "last_name": "admin cabinet",
                "phone": "979",
                "created_at": "2023-05-26T09:47:20.000000Z",
                "last_activity_at": null
            },
            "course_points": 0,
            "course_progress": {
                "course_id": 20,
                "title": "Dripping",
                "lessons_count": 9,
                "lessons_count_viewed": 2,
                "lessons_viewed_percentage": 22,
                "lessons_count_completed": 1,
                "lessons_completion_percentage": 11,
                "quizzes_count": 2,
                "quizzes_count_completed": 1,
                "quizzes_completion_percentage": 50,
                "scores_max": 200,
                "quizzes_scores": 80,
                "is_completed": false,
                "completed_at": null
            },
            "lessons_available_count": 9,
            "is_full_access": true,
            "lesson_progress": [
                {
                    "lesson_id": 48,
                    "is_watched": true,
                    "is_completed": true,
                    "quizzing_status": {
                        "id": 4,
                        "slug": "Completed",
                        "title": "Completed"
                    },
                    "watching_start_at": "2026-05-20T11:20:00.000000Z",
                    "watching_end_at": "2026-05-20T11:30:00.000000Z",
                    "quizzing_start_at": "2026-05-20T11:30:00.000000Z",
                    "quizzing_end_at": "2026-05-20T11:34:00.000000Z",
                    "completed_at": "2026-05-20T11:35:00.000000Z",
                    "created_at": "2026-05-20T11:20:00.000000Z",
                    "updated_at": "2026-05-20T11:35:00.000000Z"
                },
                {
                    "lesson_id": 46,
                    "is_watched": true,
                    "is_completed": false,
                    "quizzing_status": {
                        "id": 3,
                        "slug": "InProgress",
                        "title": "In progress"
                    },
                    "watching_start_at": "2026-05-21T09:00:00.000000Z",
                    "watching_end_at": "2026-05-21T09:10:00.000000Z",
                    "quizzing_start_at": null,
                    "quizzing_end_at": null,
                    "completed_at": null,
                    "created_at": "2026-05-21T09:00:00.000000Z",
                    "updated_at": "2026-05-21T09:10:00.000000Z"
                }
            ],
            "module_progress": [
                {
                    "module_id": 7,
                    "is_watched": true,
                    "is_completed": false,
                    "quizzing_status": {
                        "id": 3,
                        "slug": "InProgress",
                        "title": "In progress"
                    },
                    "watching_start_at": "2026-05-20T11:20:00.000000Z",
                    "watching_end_at": "2026-05-21T09:10:00.000000Z",
                    "quizzing_start_at": null,
                    "quizzing_end_at": null,
                    "completed_at": null,
                    "created_at": "2026-05-20T11:20:00.000000Z",
                    "updated_at": "2026-05-21T09:10:00.000000Z"
                }
            ],
            "quiz_progress": [
                {
                    "course_lesson_id": 48,
                    "quiz_id": 101,
                    "status": {
                        "id": 1,
                        "slug": "Passed",
                        "title": "Passed"
                    },
                    "scores": 80,
                    "scores_max": 100,
                    "started_at": "2026-05-20T11:30:00.000000Z",
                    "finished_at": "2026-05-20T11:34:00.000000Z",
                    "checked_at": null,
                    "last_activity_at": "2026-05-20T11:34:00.000000Z",
                    "attempt_number": 2
                }
            ]
        }
    ],
    "links": {
        "first": "https://api.example.com/courses/20/users?page=1",
        "last": "https://api.example.com/courses/20/users?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "https://api.example.com/courses/20/users",
        "per_page": 15,
        "to": 1,
        "total": 1
    },
    "course_structure": [
        {
            "id": 12,
            "course_nodeble_type": "course_module",
            "course_nodeble_id": 7,
            "parent_id": null,
            "order": 1,
            "course_nodeble": {
                "id": 7,
                "title": "Module title"
            },
            "children": [
                {
                    "id": 34,
                    "course_nodeble_type": "course_lesson",
                    "course_nodeble_id": 48,
                    "parent_id": 12,
                    "order": 1,
                    "course_nodeble": {
                        "id": 48,
                        "title": "Lesson 1"
                    },
                    "children": [
                        {
                            "id": 201,
                            "course_nodeble_type": "info_section",
                            "course_nodeble_id": 201,
                            "parent_id": 34,
                            "order": 1,
                            "course_nodeble": {
                                "id": 201,
                                "name": "List of practice",
                                "slug": "list-of-practice"
                            },
                            "quizzes": [
                                {"id": 101, "name": "Module wrap-up quiz"}
                            ],
                            "children": []
                        },
                        {
                            "id": 202,
                            "course_nodeble_type": "info_section",
                            "course_nodeble_id": 202,
                            "parent_id": 34,
                            "order": 2,
                            "course_nodeble": {
                                "id": 202,
                                "name": "Theory",
                                "slug": "theory"
                            },
                            "quizzes": [],
                            "children": []
                        }
                    ]
                },
                {
                    "id": 35,
                    "course_nodeble_type": "course_lesson",
                    "course_nodeble_id": 46,
                    "parent_id": 12,
                    "order": 2,
                    "course_nodeble": {
                        "id": 46,
                        "title": "Lesson 2"
                    },
                    "children": [
                        {
                            "id": 203,
                            "course_nodeble_type": "info_section",
                            "course_nodeble_id": 203,
                            "parent_id": 35,
                            "order": 1,
                            "course_nodeble": {
                                "id": 203,
                                "name": "Intro",
                                "slug": "intro"
                            },
                            "quizzes": [],
                            "children": []
                        }
                    ]
                }
            ]
        }
    ]
}

Зшивка прогресу з деревом

Ендпоінт повертає програму курсу один раз на верхньому рівні, а масиви прогресу користувача — всередині кожного рядка data[]. Щоб накласти прогрес конкретного учня на дерево, зробіть так.

1. Побудуйте словники з його масивів прогресу для швидкого пошуку.

Про імена: записи прогресу використовують lesson_id/module_id/course_lesson_id, а вузли програми — course_nodeble_id. Це одне й те саме значення, просто в різних частинах відповіді — див. крок 2.

2. Обійдіть course_program і для кожного вузла візьміть потрібний запис.

У кожного вузла є course_nodeble_type + course_nodeble_id. Використовуйте course_nodeble_id як ключ пошуку:

Якщо пошук нічого не повернув — в учня ще немає прогресу по цьому вузлу, відмалюйте порожній стан. Програма курсу однакова для всіх учнів сторінки, тому її безпечно побудувати один раз і перевикористати між рядками.

Пропозиції

Отримання списку пропозицій

Приклад запиту:

<?php
// Get offers list filtered by product

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/offers?product_id=130', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get offers list filtered by product

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/offers?product_id=130');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/offers?product_id=130' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get offers list filtered by product
const url = 'https://api.kwiga.com/offers?product_id=130';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get offers list filtered by product
import requests

url = 'https://api.kwiga.com/offers?product_id=130'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
  "data": [
    {
      "id": 273,
      "unique_offer_code": "nELQzbLRPmzo",
      "url": "https://kwiga.com/o/nELQzbLRPmzo",
      "title": "This is paid offer for my course",
      "description": "<p style=\"text-align: left\">Description with html.</p>",
      "short_description": "<p style=\"text-align: left\">Shot description with html.</p>",
      "price_type": {
        "id": 2,
        "name": "Платно"
      },
      "price": {
        "amount": "10.00",
        "amount_rounded": "10.00",
        "amount_formatted": "10.00 usd",
        "amount_formatted_code": "$10.00",
        "amount_formatted_code_short": "$10.00",
        "currency": {
          "id": 5,
          "code": "USD",
          "html_code": "$",
          "html_letter_code": "usd",
          "is_volatile": false
        }
      },
      "price_discounted": {
        "amount": 5,
        "amount_rounded": "5.00",
        "amount_formatted": "5.00 usd",
        "amount_formatted_code": "$5.00",
        "amount_formatted_code_short": "$5.00",
        "currency": {
          "id": 5,
          "code": "USD",
          "html_code": "$",
          "html_letter_code": "usd",
          "is_volatile": false
        }
      },
      "discount": {
        "id": 3,
        "price_discounted": 5,
        "limit_type": {
          "id": 1,
          "name": "Безстроково"
        },
        "start_at": "2023-12-28T14:41:00.000000Z",
        "start_at_utc": "2023-12-28T12:41:00.000000Z",
        "start_timezone_id": 371,
        "end_at": "2024-01-03T14:41:00.000000Z",
        "end_type": 3,
        "end_at_utc": "2024-01-03T12:41:00.000000Z",
        "end_timezone_id": 371,
        "sales_limit": null,
        "sales": null,
        "is_active": true,
        "is_available": true,
        "created_at": "2023-12-28T12:41:58.000000Z",
        "updated_at": "2023-12-28T12:41:58.000000Z",
        "start_timezone": {
          "id": 371,
          "name": "Europe/Kyiv",
          "name_full": "Europe/Kyiv (UTC+03:00)",
          "value": "UTC+03:00"
        },
        "end_timezone": {
          "id": 371,
          "name": "Europe/Kyiv",
          "name_full": "Europe/Kyiv (UTC+03:00)",
          "value": "UTC+03:00"
        }
      },
      "has_subscription": false,
      "limit_type": {
        "id": 1,
        "name": "Необмежено"
      },
      "limit_of_sales": null,
      "is_active": true,
      "is_draft": false,
      "validity_start": {
        "type": "validity_start",
        "duration_type_id": 1,
        "date_at": "2023-12-28T14:40:00.000000Z",
        "date_at_utc": "2023-12-28T12:40:00.000000Z",
        "timezone_id": 371,
        "timezone": {
          "id": 371,
          "name": "Europe/Kyiv",
          "name_full": "Europe/Kyiv (UTC+03:00)",
          "value": "UTC+03:00"
        },
        "after_months": 0,
        "after_days": 0,
        "specific_time": null
      },
      "validity_end": {
        "type": "validity_end",
        "duration_type_id": 3,
        "date_at": "2023-12-28T14:40:00.000000Z",
        "date_at_utc": "2023-12-28T12:40:00.000000Z",
        "timezone_id": 371,
        "timezone": {
          "id": 371,
          "name": "Europe/Kyiv",
          "name_full": "Europe/Kyiv (UTC+03:00)",
          "value": "UTC+03:00"
        },
        "after_months": 0,
        "after_days": 0,
        "specific_time": null
      },
      "products": [
        {
          "id": 130,
          "productable_id": 38,
          "productable_type": "course",
          "title": "This is my course",
          "link": "https://kwiga.com/courses/test-fail"
        }
      ]
    },
    {
      "id": 272,
      "unique_offer_code": "2obtMsUEujcy",
      "url": "https://kwiga.com/o/2obtMsUEujcy",
      "title": "This is free offer for my course",
      "description": null,
      "short_description": null,
      "price_type": {
        "id": 1,
        "name": "Безкоштовно"
      },
      "price": {
        "amount": "0.00",
        "amount_rounded": "0.00",
        "amount_formatted": "0.00 usd",
        "amount_formatted_code": "$0.00",
        "amount_formatted_code_short": "$0.00",
        "currency": {
          "id": 5,
          "code": "USD",
          "html_code": "$",
          "html_letter_code": "usd",
          "is_volatile": false
        }
      },
      "price_discounted": {
        "amount": 0,
        "amount_rounded": "0.00",
        "amount_formatted": "0.00 usd",
        "amount_formatted_code": "$0.00",
        "amount_formatted_code_short": "$0.00",
        "currency": {
          "id": 5,
          "code": "USD",
          "html_code": "$",
          "html_letter_code": "usd",
          "is_volatile": false
        }
      },
      "discount": null,
      "has_subscription": false,
      "limit_type": {
        "id": 1,
        "name": "Необмежено"
      },
      "limit_of_sales": null,
      "is_active": true,
      "is_draft": false,
      "validity_start": {
        "type": "validity_start",
        "duration_type_id": 1,
        "date_at": "2023-12-27T12:45:00.000000Z",
        "date_at_utc": "2023-12-27T10:45:00.000000Z",
        "timezone_id": 371,
        "timezone": {
          "id": 371,
          "name": "Europe/Kyiv",
          "name_full": "Europe/Kyiv (UTC+03:00)",
          "value": "UTC+03:00"
        },
        "after_months": 0,
        "after_days": 0,
        "specific_time": null
      },
      "validity_end": {
        "type": "validity_end",
        "duration_type_id": 3,
        "date_at": "2023-12-27T12:45:00.000000Z",
        "date_at_utc": "2023-12-27T10:45:00.000000Z",
        "timezone_id": 371,
        "timezone": {
          "id": 371,
          "name": "Europe/Kyiv",
          "name_full": "Europe/Kyiv (UTC+03:00)",
          "value": "UTC+03:00"
        },
        "after_months": 0,
        "after_days": 0,
        "specific_time": null
      },
      "products": [
        {
          "id": 130,
          "productable_id": 38,
          "productable_type": "course",
          "title": "This is my course",
          "link": "https://kwiga.com/courses/test-fail"
        }
      ]
    }
  ],
  "links": {
    "first": "http://api.kwiga.local/offers?page=1",
    "last": "http://api.kwiga.local/offers?page=1",
    "prev": null,
    "next": null
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 1,
    "links": [
      {
        "url": null,
        "label": "&laquo; Previous",
        "active": false
      },
      {
        "url": "http://api.kwiga.local/offers?page=1",
        "label": "1",
        "active": true
      },
      {
        "url": null,
        "label": "Next &raquo;",
        "active": false
      }
    ],
    "path": "http://api.kwiga.local/offers",
    "per_page": 15,
    "to": 1,
    "total": 2
  }
}

GET https://api.kwiga.com/offers

URL Parameters

page integer optional
Номер сторінки
per_page integer optional
Кількість елементів вибірки
product_id integer optional
Фільтр по продукту
filters object optional
Filter parameters
search string optional
Пошуковий запит

Структура відповіді

Елементи поточної сторінки.
Посилання на інші сторінки того самого списку.
Стан пагінації для поточного запиту (номер сторінки, загальна кількість тощо).

Отримання пропозиції

Приклад запиту:

<?php
// Get offer by ID

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/offers/{id}', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get offer by ID

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/offers/{id}');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/offers/{id}' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get offer by ID
const url = 'https://api.kwiga.com/offers/{id}';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get offer by ID
import requests

url = 'https://api.kwiga.com/offers/{id}'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
  "data": {
    "id": 1,
    "unique_offer_code": "6rT1wj99lbZV",
    "title": "Offer #1",
    "limit_type": {
      "id": 2,
      "name": "Certain amount"
    },
    "limit_of_sales": 20,
    "purchases_count": 1,
    "sales_left": 19
  }
}

GET https://api.kwiga.com/offers/:offer

Структура відповіді

Маркетинг. Розсилка

Список списків контактів

Приклад запиту:

<?php
// Get contact lists

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/mailing/contact-lists', $options);

$result = json_decode($response->getBody());
?>


# ---
# Paginated example
# ---

<?php
// Get contact lists with pagination

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/mailing/contact-lists?page=1&per_page=15', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get contact lists

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/mailing/contact-lists');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>


# ---
# Paginated example
# ---

<?php
// Get contact lists with pagination

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/mailing/contact-lists?page=1&per_page=15');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/mailing/contact-lists' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'


# ---
# Paginated example
# ---

curl --location --request GET 'https://api.kwiga.com/mailing/contact-lists?page=1&per_page=15' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get contact lists
const url = 'https://api.kwiga.com/mailing/contact-lists';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });


# ---
# Paginated example
# ---

// Get contact lists with pagination
const url = 'https://api.kwiga.com/mailing/contact-lists?page=1&per_page=15';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get contact lists
import requests

url = 'https://api.kwiga.com/mailing/contact-lists'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()


# ---
# Paginated example
# ---

# Get contact lists with pagination
import requests

url = 'https://api.kwiga.com/mailing/contact-lists?page=1&per_page=15'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
  "data": [
    {
        "id": 2,
        "title": "Пример 2",
        "description": "Описание",
        "is_default": false,
        "created_at": "2022-04-28T13:22:44.000000Z",
        "updated_at": "2022-04-28T13:22:44.000000Z"
    },
    {
        "id": 1,
        "title": "Мой первый список",
        "description": "Данный список создаётся автоматически с вашим контактом внутри. Вы можете его отредактировать под свои потребности.",
        "is_default": true,
        "created_at": "2022-04-28T12:47:08.000000Z",
        "updated_at": "2022-04-28T12:47:08.000000Z"
    }
  ],
  "links": {
        "first": "https://api.kwiga.com/mailing/contact-lists?page=1",
        "last": "https://api.kwiga.com/mailing/contact-lists?page=2",
        "prev": null,
        "next": "https://api.kwiga.com/mailing/contact-lists?page=2"
   },
   "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 2,
        "links": [
            {
                "url": null,
                "label": "&laquo; translation missing: ua.pagination_prev",
                "active": false
            },
            {
                "url": "https://api.kwiga.com/mailing/contact-lists?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": "https://api.kwiga.com/mailing/contact-lists?page=2",
                "label": "2",
                "active": false
            },
            {
                "url": "https://api.kwiga.com/mailing/contact-lists?page=2",
                "label": "translation missing: ua.pagination_next &raquo;",
                "active": false
            }
        ],
        "path": "https://api.kwiga.com/mailing/contact-lists",
        "per_page": 2,
        "to": 2,
        "total": 3
    }
}

GET https://api.kwiga.com/mailing/contact-lists

URL Parameters

page integer optional
Номер сторінки
limit integer optional
Кількість елементів вибірки

Структура відповіді

Елементи поточної сторінки.

Посилання на інші сторінки того самого списку.
Стан пагінації для поточного запиту (номер сторінки, загальна кількість тощо).

Отримання списку контактів

Приклад запиту:

<?php
// Get contact list by ID

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/mailing/contact-lists/{id}', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get contact list by ID

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/mailing/contact-lists/{id}');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/mailing/contact-lists/{id}' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get contact list by ID
const url = 'https://api.kwiga.com/mailing/contact-lists/{id}';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get contact list by ID
import requests

url = 'https://api.kwiga.com/mailing/contact-lists/{id}'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
  "data": {
    "id": 1,
    "title": "Мой первый список",
    "description": "Данный список создаётся автоматически с вашим контактом внутри. Вы можете его отредактировать под свои потребности.",
    "is_default": true,
    "created_at": "2022-04-28T12:47:08.000000Z",
    "updated_at": "2022-04-28T12:47:08.000000Z",
    "contacts": [
        {
            "id": 1,
            "first_name": "Alex",
            "middle_name": null,
            "last_name": "Иванович Burt",
            "name": "Иванович Burt Alex",
            "sex": null,
            "age": null,
            "email": "admin@grandstep.com.ua",
            "phone_country": "UA",
            "phone_number": "983721222",
            "city": null,
            "phone": "+380983721222",
            "created_at": "2022-04-28T12:47:07.000000Z",
            "updated_at": "2022-04-28T12:47:08.000000Z"
        }
    ],
    "statistic": {
        "contact_list_id": 1,
        "count_contacts": 1
    }
}
}

GET https://api.kwiga.com/mailing/contact-lists/:list

Структура відповіді

Створення списку контактів

Приклад запиту:

<?php
// Create contact list

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
    'json' => [
        'title' => 'Название группы',
        'description' => 'описание',
    ],
];

$response = $client->request('POST', '/mailing/contact-lists/', $options);

$result = json_decode($response->getBody());
?>
<?php
// Create contact list

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/mailing/contact-lists/');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

$data = [
    'title' => 'Название группы',
    'description' => 'описание',
];

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request POST 'https://api.kwiga.com/mailing/contact-lists/' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"title":"Название группы","description":"описание"}'
// Create contact list
const url = 'https://api.kwiga.com/mailing/contact-lists/';

const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
  body: JSON.stringify({
    'title': 'Название группы',
    'description': 'описание'
  })
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Create contact list
import requests

url = 'https://api.kwiga.com/mailing/contact-lists/'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

data = {
    'title': 'Название группы',
    'description': 'описание',
}

response = requests.post(url, headers=headers, json=data)

result = response.json()

Приклад відповіді:

{
    "data": {
        "id": 3,
        "title": "fsdaf asfsf dsafsda fsda",
        "description": "1dsad sadsa ds dsa",
        "is_default": false,
        "created_at": "2022-05-04T09:57:37.000000Z",
        "updated_at": "2022-05-04T09:57:37.000000Z"
    }
}

POST https://api.kwiga.com/mailing/contact-lists

Request

title string required
Назва
description string optional
Опис

Структура відповіді

Додавання контактів до списку

Приклад запиту:

<?php
// Bulk add contacts to lists

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
    'json' => [
        'contacts[]' => 1,
        'contacts[]' => 2,
        'contact_lists[]' => 1,
    ],
];

$response = $client->request('POST', '/mailing/contact-lists/bulk-contacts', $options);

$result = json_decode($response->getBody());
?>
<?php
// Bulk add contacts to lists

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/mailing/contact-lists/bulk-contacts');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

$data = [
    'contacts[]' => 1,
    'contacts[]' => 2,
    'contact_lists[]' => 1,
];

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request POST 'https://api.kwiga.com/mailing/contact-lists/bulk-contacts' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"contacts[]":2,"contact_lists[]":1}'
// Bulk add contacts to lists
const url = 'https://api.kwiga.com/mailing/contact-lists/bulk-contacts';

const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
  body: JSON.stringify({
    'contacts[]': 1,
    'contacts[]': 2,
    'contact_lists[]': 1
  })
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Bulk add contacts to lists
import requests

url = 'https://api.kwiga.com/mailing/contact-lists/bulk-contacts'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

data = {
    'contacts[]': 1,
    'contacts[]': 2,
    'contact_lists[]': 1,
}

response = requests.post(url, headers=headers, json=data)

result = response.json()

Приклад відповіді:

{
    "success": true
}

POST https://api.kwiga.com/mailing/contact-lists/bulk-contacts

URL Parameters

contacts integer[] required
Контакти (ID)
contact_lists integer[] required
Списки контактів (ID)

Структура відповіді

Тіло відповіді повертається без обгортки.

Продажі. Купони

Список купонів

Приклад запиту:

<?php
// Get coupons list

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/coupons', $options);

$result = json_decode($response->getBody());
?>


# ---
# Filtered example
# ---

<?php
// Get coupons list with date filters

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/coupons?filters[date_from]=2022-04-15&filters[date_to]=2022-04-27', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get coupons list

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/coupons');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>


# ---
# Filtered example
# ---

<?php
// Get coupons list with date filters

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/coupons?filters[date_from]=2022-04-15&filters[date_to]=2022-04-27');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/coupons' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'


# ---
# Filtered example
# ---

curl --location --request GET 'https://api.kwiga.com/coupons?filters[date_from]=2022-04-15&filters[date_to]=2022-04-27' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get coupons list
const url = 'https://api.kwiga.com/coupons';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });


# ---
# Filtered example
# ---

// Get coupons list with date filters
const url = 'https://api.kwiga.com/coupons?filters[date_from]=2022-04-15&filters[date_to]=2022-04-27';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get coupons list
import requests

url = 'https://api.kwiga.com/coupons'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()


# ---
# Filtered example
# ---

# Get coupons list with date filters
import requests

url = 'https://api.kwiga.com/coupons?filters[date_from]=2022-04-15&filters[date_to]=2022-04-27'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
    "data": [
        {
            "id": 3,
            "code": "KwigaSMVT-MD",
            "reward": 30,
            "is_fixed": true,
            "is_disposable": false,
            "used_amount": 0,
            "total_uses": 10,
            "total_uses_per_user": 1,
            "user": {
                "id": 3,
                "avatar_url": "https://someurl.com",
                "hash": "EL9p2ycy4Ypga715",
                "name": "Test User",
                "email": "test@example.com",
                "tag_name": "TestUser"
            },
            "created_at": "2022-04-28T09:46:11.000000Z",
            "updated_at": "2022-04-28T09:46:11.000000Z",
            "deleted_at": null
        }
    ]
}

GET https://api.kwiga.com/coupons

URL Parameters

filters object optional
Filter parameters
date_from datetime optional
Фільтр за датою створення. Параметр 'від'
date_to datetime optional
Фільтр за датою створення. Параметр 'до'

Структура відповіді

Елементи поточної сторінки.
Посилання на інші сторінки того самого списку.
Стан пагінації для поточного запиту (номер сторінки, загальна кількість тощо).

Отримання купона

Приклад запиту:

<?php
// Get coupon by ID

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/coupons/{id}', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get coupon by ID

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/coupons/{id}');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/coupons/{id}' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get coupon by ID
const url = 'https://api.kwiga.com/coupons/{id}';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get coupon by ID
import requests

url = 'https://api.kwiga.com/coupons/{id}'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
    "data": {
        "id": 1,
        "code": "KwigaSMVT-MD",
        "reward": 30,
        "is_fixed": true,
        "is_disposable": false,
        "used_amount": 0,
        "total_uses": 10,
        "total_uses_per_user": 1,
        "created_at": "2022-04-28T09:46:11.000000Z",
        "updated_at": "2022-04-28T09:46:11.000000Z",
        "deleted_at": null
    }
}

GET https://api.kwiga.com/coupons/:coupon

Структура відповіді

Створити купон

Приклад запиту:

<?php
// Create coupon

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
    'json' => [
        'code' => 'MY-COUPON',
        'reward' => 0,
        'type_discount[id]' => 'discount_with_percent',
        'expires_at' => ,
        'timezone[id]' => 375,
        'total_uses' => 0,
        'total_uses_per_user' => 0,
    ],
];

$response = $client->request('POST', '/coupons', $options);

$result = json_decode($response->getBody());
?>
<?php
// Create coupon

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/coupons');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

$data = [
    'code' => 'MY-COUPON',
    'reward' => 0,
    'type_discount[id]' => 'discount_with_percent',
    'expires_at' => ,
    'timezone[id]' => 375,
    'total_uses' => 0,
    'total_uses_per_user' => 0,
];

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request POST 'https://api.kwiga.com/coupons' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"code":"MY-COUPON","reward":0,"type_discount[id]":"discount_with_percent","expires_at":null,"timezone[id]":375,"total_uses":0,"total_uses_per_user":0}'
// Create coupon
const url = 'https://api.kwiga.com/coupons';

const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
  body: JSON.stringify({
    'code': 'MY-COUPON',
    'reward': 0,
    'type_discount[id]': 'discount_with_percent',
    'expires_at': ,
    'timezone[id]': 375,
    'total_uses': 0,
    'total_uses_per_user': 0
  })
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Create coupon
import requests

url = 'https://api.kwiga.com/coupons'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

data = {
    'code': 'MY-COUPON',
    'reward': 0,
    'type_discount[id]': 'discount_with_percent',
    'expires_at': ,
    'timezone[id]': 375,
    'total_uses': 0,
    'total_uses_per_user': 0,
}

response = requests.post(url, headers=headers, json=data)

result = response.json()

Приклад відповіді:

{
    "data": {
        "id": 8,
        "code": "MY-COUPON",
        "reward": 100,
        "type_discount": {
            "id": "discount_with_percent",
            "name": "In % of order/offer value"
        },
        "type_date_expired": {
            "id": "indefinite_action",
            "name": "Never expires"
        },
        "type_total_count_used": {
            "id": "certain_amount",
            "name": "A certain amount"
        },
        "type_used_contact_lists": {
            "id": "all_users",
            "name": "All users"
        },
        "is_fixed": false,
        "is_active": true,
        "used_amount": 0,
        "has_infinite_used": true,
        "has_access_contact_lists": false,
        "total_uses": 0,
        "total_uses_per_user": 1,
        "contact_lists": [],
        "type": {
            "id": 4,
            "title": "Offers"
        },
        "expires_at": null,
        "expires_at_utc": null,
        "timezone_id": null,
        "currency_id": null,
        "currency": null,
        "created_at": "2024-01-09T16:17:55.000000Z",
        "updated_at": "2024-01-09T16:17:55.000000Z",
        "deleted_at": null
    }
}

POST https://api.kwiga.com/coupons

URL Parameters

code string optional
Код купону. Якщо не вказати, код згенерується автоматично
type_discount.id string required
Тип знижки: відсоток від суми - `discount_with_percent` або фіксована знижка - `discount_with_currency`
Example: discount_with_percent or discount_with_currency
expires_at datetime optional
Термін дії купона. Якщо null чи не вказувати, то безстроково
Example: 2024-12-31 or 2024-12-31 23:59:59
timezone.id integer optional
Таймзона дати терміну дії купона
total_uses integer optional
Ліміт на кількість використань купона. 0 - без обмежень
total_uses_per_user integer optional
Ліміт на кількість використань купона одним користувачем

Структура відповіді

Перевірка купона

Приклад запиту:

<?php
// Check coupon validity

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
    'json' => [
        'code' => 'VAJ6-EA',
        'price' => 65,
    ],
];

$response = $client->request('POST', '/coupons/check', $options);

$result = json_decode($response->getBody());
?>
<?php
// Check coupon validity

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/coupons/check');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');

$data = [
    'code' => 'VAJ6-EA',
    'price' => 65,
];

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request POST 'https://api.kwiga.com/coupons/check' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"code":"VAJ6-EA","price":65}'
// Check coupon validity
const url = 'https://api.kwiga.com/coupons/check';

const options = {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
  body: JSON.stringify({
    'code': 'VAJ6-EA',
    'price': 65
  })
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Check coupon validity
import requests

url = 'https://api.kwiga.com/coupons/check'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

data = {
    'code': 'VAJ6-EA',
    'price': 65,
}

response = requests.post(url, headers=headers, json=data)

result = response.json()

Приклад відповіді:

{
  "data": {
    "can_use": true,
    "discount": 6.5
  }
}

POST https://api.kwiga.com/coupons/check

Перевіряє купон на існування і можливість використання (не вичерпано ліміт / не закінчився термін дії).
Зверніть увагу: при використанні на checkout сторінці купон може не застосовуватися при наступних умовах: якщо на пропозиції вимкнено використання купонів/даного купона; на купоні є обмеження списками контактів; користувач вже використовував купон і на купоні є обмеження по кількості використань.

Parameters

code string required
Код купона для перевірки
price number optional
Ціна для розрахунку знижки. Якщо вказати, то у відповіді буде повернуто значення знижки у полі discount

Структура відповіді

Сертифікати

Отримання сертифікат за номером

Приклад запиту:

<?php
// Get certificate by number

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/certificates/by-number/{number}', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get certificate by number

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/certificates/by-number/{number}');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/certificates/by-number/{number}' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get certificate by number
const url = 'https://api.kwiga.com/certificates/by-number/{number}';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get certificate by number
import requests

url = 'https://api.kwiga.com/certificates/by-number/{number}'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
    "data": {
        "id": 55,
        "uuid": "262e7042-1933-42a9-ba01-e96d7d5110dc",
        "cabinet_id": 1,
        "user_id": 273,
        "issued_at": "2023-07-25T15:36:44.000000Z",
        "number": "1986-0001",
        "link": "http://cabinet-1.kwiga.local/certificates/262e7042-1933-42a9-ba01-e96d7d5110dc",
        "created_at": "2023-07-25T15:36:44.000000Z",
        "updated_at": "2023-07-25T15:36:44.000000Z",
        "finished_at": "2023-07-25T15:36:44.000000Z",
        "points": 120,
        "user": {
            "id": 273,
            "name": "test name",
            "email": "test-student@kwiga.com"
        },
        "certificateble_title": "Test course"
    }
}

GET https://api.kwiga.com/certificates/by-number/:number

Структура відповіді

Таймзони

Отримання списку таймзон

Приклад запиту:

<?php
// Get timezones list

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.kwiga.com']);

$options = [
    'headers' => [
        'Accept' => 'application/json',
        'Token' => '<Token>',
        'Cabinet-Hash' => '<Cabinet-Hash>',
    ],
];

$response = $client->request('GET', '/timezones', $options);

$result = json_decode($response->getBody());
?>
<?php
// Get timezones list

$headers = [
    'Accept: application/json',
    'Token: <Token>',
    'Cabinet-Hash: <Cabinet-Hash>',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/timezones');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response);
?>
curl --location --request GET 'https://api.kwiga.com/timezones' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get timezones list
const url = 'https://api.kwiga.com/timezones';

const options = {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
  },
};

fetch(url, options)
  .then(response => response.json())
  .then(result => {
    console.log(result);
  })
  .catch(error => {
    console.error('Error:', error);
  });
# Get timezones list
import requests

url = 'https://api.kwiga.com/timezones'

headers = {
    'Accept': 'application/json',
    'Token': '<Token>',
    'Cabinet-Hash': '<Cabinet-Hash>',
}

response = requests.get(url, headers=headers)

result = response.json()

Приклад відповіді:

{
    "data": [
        {
            "id": 1,
            "name": "Asia/Kabul",
            "name_full": "Asia/Kabul (UTC+04:30)",
            "value": "UTC+04:30"
        },
        {
            "id": 2,
            "name": "Europe/Tirane",
            "name_full": "Europe/Tirane (UTC+02:00)",
            "value": "UTC+02:00"
        },
        ...
    ]
}

GET https://api.kwiga.com/timezones

Структура відповіді

Елементи поточної сторінки.
Посилання на інші сторінки того самого списку.
Стан пагінації для поточного запиту (номер сторінки, загальна кількість тощо).

Схеми даних

Перевикористовувані об'єкти відповідей API. Поля з позначкою conditional з'являються у відповіді лише за виконання документованої умови (прапор запиту, опціональний include чи певний ендпоінт).

Контакти

Contact

id integer
Унікальний ідентифікатор контакту
user_id integer nullable
Ідентифікатор пов'язаного користувача (null, якщо у контакту ще немає акаунту користувача)
email string
Email контакту
first_name string nullable
middle_name string nullable
last_name string nullable
name string nullable
Відображуване ім'я, зібране з імені/по-батькові/прізвища у порядку, прийнятому в кабінеті.
phone string nullable
crm_link string nullable
Пряме посилання на сторінку контакту у CRM вашого кабінету.
created_at datetime
Момент створення контакту
tags FlowTag[] conditional
Conditional: Included when tags are loaded for the contact.
Теги, прикріплені до контакту
last_activity_at datetime conditional
Conditional: Included when the contact has activity history in the cabinet.
Момент останньої активності контакту в кабінеті
first_visit Visit conditional
Conditional: Included when the contact has at least one recorded visit.
Перший зафіксований візит контакту
utm UtmList conditional
Conditional: Included when UTM data has been collected for the contact.
Агрегована UTM-атрибуція за всіма візитами контакту
utm_visits Visit[] conditional
Conditional: Returned only on `GET /contacts/{id}` — not present on the contacts list.
Усі UTM-відстежені візити контакту
offers Offer[] conditional
Conditional: Included when `with_orders=true` is passed.
Пропозиції, куплені контактом
orders Order[] conditional
Conditional: Included when `with_orders=true` is passed.
Замовлення, розміщені контактом
Conditional: Included when the contact has custom field values configured.
Кастомні поля кабінету, заповнені для цього контакту
Conditional: Included when `with_certificates=true` is passed.
Інформація про випущені сертифікати за продуктами контакту

ContactIdentifier

id integer
user_id integer nullable
first_name string nullable
last_name string nullable
name string nullable
Повне ім'я контакту (ім'я + прізвище), якщо вказано
email string nullable
Email контакту (може бути прихований для не-власників)
phone string nullable
Телефон контакту (може бути прихований для не-власників)

ContactAdditionalField

field ContactField conditional
Conditional: Included when the field definition is part of the response.
Визначення кастомного поля кабінету
value string nullable
Сире значення, збережене для цього поля на контакті
display_value string nullable
Читаюче відображення значення (наприклад, локалізований enum-label)

ContactField

id integer
title string
Локалізована назва поля
is_local boolean
Чи є поле локальним для кабінету (не частиною глобальної схеми)
input_title string conditional
Conditional: Returned only for viewers with extended access to the field.
format string conditional
Conditional: Returned only for viewers with extended access to the field.
Токен формату вводу для поля
validation string conditional
Conditional: Returned only for viewers with extended access to the field.
Вираз правила валідації
default_value string conditional
Conditional: Returned only for viewers with extended access to the field.
placeholder string conditional
Conditional: Returned only for viewers with extended access to the field.
type string conditional
Conditional: Returned only for viewers with extended access to the field.
Ідентифікатор типу поля (text, number, date, enum тощо)
is_default boolean conditional
Conditional: Returned only for viewers with extended access to the field.
is_required boolean conditional
Conditional: Returned only for viewers with extended access to the field.
is_at_import boolean conditional
Conditional: Returned only for viewers with extended access to the field.
visible_type Enum conditional
Conditional: Returned only for viewers with extended access to the field.
order integer conditional
Conditional: Returned only for viewers with extended access to the field.
Порядок відображення всередині кабінету
values object[] conditional
Conditional: Returned for viewers with extended access when value options are configured.
Допустимі значення для enum-полів
name_order_type object conditional
Conditional: Returned for viewers with extended access when the field is the default full-name field.
Порядок відображення імені/прізвища, заданий у кабінеті

ContactList

id integer
cabinet_id integer conditional
Conditional: Included when the cabinet relation is part of the response.
Ідентифікатор кабінету-власника
user_id integer conditional
Conditional: Included when the owning user is part of the response.
Ідентифікатор користувача-власника
title string
description string nullable
is_default boolean
True для вбудованого списку за замовчуванням у кабінеті
is_active boolean
is_segment boolean
True, якщо список — динамічний сегмент, керований фільтрами
is_new boolean
Маркер для списків, створених після 2023-08-15 (використовується в UI)
paused_at datetime nullable
created_at datetime
updated_at datetime
contacts_count integer conditional
Conditional: Included when contact counts are available for the list.
Conditional: Returned on the single-list endpoint; not present on the list response.
Conditional: Included when list statistics are part of the response.
Conditional: Included when the list's email campaigns are part of the response.
Email-розсилки, пов'язані зі списком
segment_settings object conditional
Conditional: Present for dynamic segments; empty object for regular lists.
Правила фільтрації, що визначають членство в сегменті

ContactListStatistic

contact_list_id integer
count_contacts integer
Кількість контактів, які зараз у списку

FlowTag

id integer
name string
contacts_count integer conditional
Conditional: Included when contact counts are available for the tag.
Скільки контактів позначено цим тегом

Курси

Course

id integer
product_id integer
Ідентифікатор пов'язаного продукту (для пошуку через /contacts/{contact}/products)
type string
Ідентифікатор типу курсу (course / marathon / тощо)
title string
Назва курсу (фолбек на `Course
slug string nullable
URL-сумісний slug
preview FileSimple conditional
Conditional: Included when the course has a preview image.
link string
Публічне посилання на лендінг курсу
status string
Ідентифікатор статусу публікації курсу (`draft`, `published` тощо)
offers Offer[] conditional
Conditional: Included when the course offers are part of the response.
info_units InfoUnit[] conditional
Conditional: Included when course info units are part of the response.
Conditional: Included when the course program is part of the response (rendered as a tree).

CourseIdentify

id integer
product_id integer
Ідентифікатор пов'язаного продукту
type_id integer
Ідентифікатор типу курсу (course / marathon / тощо)
title string
Conditional: Included when the course's lesson identity payloads are loaded.
Короткі ідентифікаційні записи уроків курсу
link string
Публічне посилання на лендінг курсу
preview_url string conditional
Conditional: Included when the course preview is loaded.
URL прев'ю-картинки курсу (або плейсхолдер за замовчуванням, якщо зображення не задано)
Conditional: Included when offer identity payloads tied to the course are loaded.
Короткі ідентифікаційні записи пропозицій, пов'язаних з курсом

CourseLessonIdentify

id integer
title string
course CourseIdentify conditional
Conditional: Included when the parent course identity is part of the response.
Conditional: Included when the lesson's module branch is part of the response. Null for top-level lessons.

CourseLessonSimple

id integer
course_id integer
type_id integer
Ідентифікатор типу уроку
status_id integer
Ідентифікатор статусу публікації уроку
number string nullable
Видимий користувачу номер уроку (токен порядку глави)
title string
slug string nullable
link string
Публічне посилання на урок
Conditional: Included when lesson quizzes are part of the response.
Квізи, прикріплені до уроку
course CourseIdentify conditional
Conditional: Included when the parent course summary is part of the response.
Ідентифікаційні дані батьківського курсу
Зведення батьківського модуля; null для уроків верхнього рівня

CourseModuleSimple

id integer
course_id integer
number string nullable
Видимий користувачу номер модуля / токен порядку
title string

CourseProgram

id integer
order integer
Позиція серед сусідніх вузлів
Поліморфний тип нижчележачої сутності (урок, модуль тощо)
course_id integer
title string
Назва нижчележачої сутності
preview FileSimple conditional
Conditional: Included when the node has a preview image attached.
Вкладені дочірні вузли (порожній масив у листків)
root_id integer nullable
Ідентифікатор кореня дерева
parent_id integer nullable
is_public boolean
link string nullable
Публічне посилання на вузол (якщо застосовно)

CourseProgress

course_id integer
course_url string
Публічне посилання на лендінг курсу
title string
Назва курсу
lessons_count integer
Загальна кількість активних уроків у курсі
Кількість уроків, відкритих користувачем хоча б раз
Відсоток переглянутих користувачем уроків (0 – 100)
Кількість пройдених користувачем уроків
Відсоток пройдених користувачем уроків (0 – 100)
Відсоток проходження для відображення (обрізаний/округлений для UI)
quizzes_count integer
Загальна кількість квізів у курсі
Кількість пройдених користувачем квізів
Відсоток пройдених користувачем квізів (0 – 100)
scores_max number
Максимально можливий бал користувача за курс
Сумарний бал користувача за всіма квізами
Сумарний бал користувача на рівні продукту (поза квізами)
scores number
Сумарний бал користувача за всім курсом
is_completed boolean
True, якщо користувач повністю пройшов курс
completed_at datetime nullable
Момент повного завершення курсу; null поки курс у процесі
Урок, на якому користувач зараз знаходиться (null, якщо немає)
Наступний доступний користувачу урок (null у кінці курсу)
last_active_at datetime nullable
Момент останньої активності користувача в курсі
True, якщо користувач пропустив блокувальні чекпоінти
Чекпоінт-квізи, до яких дійшов користувач
True, якщо користувач обійшов поточний drip-content бар'єр
True, якщо користувач обійшов наступний drip-content бар'єр
current_dripping_date datetime nullable
Коли розблоковується поточний drip-content бар'єр
next_dripping_date datetime nullable
Коли розблоковується наступний drip-content бар'єр

CourseUser

Акаунт учня, який бере участь у курсі — ідентифікатор, ім'я, email. Стабільно між запитами.
Пов'язаний запис CRM-контакту для цього учня.
course_points integer
Загальна кількість балів користувача в курсі
Зведення проходження уроків/модулів
Кількість уроків, доступних користувачу зараз
is_full_access boolean
True, якщо у користувача є доступ до всіх активних уроків курсу
Conditional: Included when the user has an aggregated subscription for the course.
Conditional: Included when include contains lesson_progress.
Масив об'єктів `LessonProgress` — per-lesson знімки перегляду/завершення для цього користувача. Повертається при `include=lesson_progress`.
Conditional: Included when include contains module_progress.
Масив об'єктів `ModuleProgress` — per-module знімки перегляду/завершення для цього користувача (агрегуються сервером з уроків модуля). Повертається при `include=module_progress`.
Conditional: Included when include contains quiz_progress.
Масив об'єктів `QuizProgress` — по одному запису на пару `(course_lesson_id, quiz_id)` зі зведенням за останньою non-cancelled спробою учня. Повертається при `include=quiz_progress`.

InfoUnit

id integer
title string
description_formatted string nullable
Опис з rich-text форматуванням та обробленими посиланнями
True, якщо опис містить зовнішні посилання
position integer
Позиція елемента в батьківській колекції
type_id integer
Ідентифікатор типу info-unit

QuizIdentifier

id integer
name string
Назва квіза

QuizAttemptIdentifier

id integer
course_id integer nullable
quiz_id integer
user_id integer
status_id integer
Ідентифікатор статусу спроби (passed / failed / in-progress)
comment string nullable
quiz object conditional
Conditional: Included when the quiz relation is loaded.
Метадані квіза
course Course conditional
Conditional: Included when the parent course is loaded.
lesson object conditional
Conditional: Included when the parent lesson is loaded.
Метадані уроку

Купони

ExpertCoupon

id integer
code string
Код купона, який покупці вводять при оформленні
reward number nullable
Значення винагороди (сума знижки або відсоток залежно від `is_fixed`)
Тип знижки (enum-payload)
Тип правила закінчення (enum-payload)
is_fixed boolean
True для знижки у валюті, false для відсоткової
is_active boolean
used_amount integer
Скільки разів купон було використано
Чи обмежено використання купона певними списками контактів
total_uses integer nullable
Максимальна загальна кількість використань купона
total_uses_per_user integer nullable
Максимум використань на один контакт
Conditional: Included when the coupon's contact-list restrictions are part of the response.
type CouponType conditional
Conditional: Included when the coupon-type metadata is part of the response.
Метадані типу купона
expert UserSimple conditional
Conditional: Included when the expert who owns the coupon is part of the response.
user UserSimple conditional
Conditional: Included when the issuing user is part of the response.
contact_id integer nullable
Conditional: Included when the linked contact is part of the response.
Короткі ідентифікаційні дані пов'язаного контакту
Conditional: Included when the offers limited by this coupon are part of the response.
Ідентифікаційні дані пропозицій, на які діє купон
expires_at datetime nullable
expires_at_utc datetime nullable
timezone_id integer nullable
timezone Timezone conditional
Conditional: Included when the coupon has timezone settings configured.
Conditional: Included when the latest internal comment is part of the response.
Останній внутрішній коментар (для адміністраторів)
currency_id integer nullable
currency Currency nullable
created_at datetime
updated_at datetime
deleted_at datetime nullable

CouponType

id integer
title string
Локалізована назва типу купона

CouponCheck

can_use boolean
Чи можна застосувати купон до замовлення
discount number nullable
Обчислена сума знижки, якщо у запиті передавався `price`; інакше null

Сертифікати

Certificate

id integer
uuid string
Універсальний унікальний ідентифікатор сертифіката
cabinet_id integer
user_id integer nullable
number string
Публічний номер сертифіката для пошуку
link string nullable
Публічне посилання для перевірки; `null` поки сертифікат не випущено
issued_at datetime nullable
finished_at datetime conditional
Conditional: Included when both the user and the certificate target are available in the response.
Коли користувач завершив certificateble-сутність (курс тощо)
points integer conditional
Conditional: Included when both the user and the certificate target are available in the response.
Бали, набрані користувачем для отримання сертифіката
user UserSimple conditional
Conditional: Included when the related user is part of the response.
creator UserSimple conditional
Conditional: Included when creator information is part of the response.
Conditional: Included when the certificate template is part of the response.
Назва сутності, на яку випущено сертифікат (курс, продукт тощо)

CertificateTemplate

id integer
title string
Внутрішня назва шаблону
public_title string nullable
Публічна назва шаблону, що відображається на випущеному сертифікаті

StudentProductCertificateInfo

Тип сертифіката (enum-payload з id/title)
Conditional: Included when the certificate template is part of the response.
Поліморфний тип certificateble-сутності (курс, продукт тощо)
certificateble_title string conditional
Conditional: Included when the certificate target is part of the response.
Назва certificateble-сутності
message string nullable
system_comment string nullable
certificate Certificate conditional
Conditional: Returned only after the certificate has been issued.

Пропозиції

Offer

id integer
unique_offer_code string nullable
Стабільний код, що використовується в URL оплати
url string
Публічний URL для купівлі пропозиції
title string
description string nullable
short_description string nullable
price_type string
Ідентифікатор моделі ціни пропозиції (`free`, `fixed`, `recurring`)
price_discounted Price conditional
Conditional: Included when the offer has an active discount.
Ціна із застосованою активною знижкою
discount OfferDiscount conditional
Conditional: Included when the offer has an active, currently valid discount.
limit_type string nullable
Ідентифікатор типу обмеження продажів (`unlimited`, `limited`)
limit_of_sales integer nullable
Максимум дозволених покупок (null якщо без ліміту)
purchases_count integer conditional
Conditional: Included when purchase counts are available for the offer.
sales_left integer conditional
Conditional: Included when purchase counts are available. Null when the offer has no sales limit.
is_draft boolean
is_active boolean conditional
Conditional: Included when the offer has date settings configured.
Conditional: Returned together with `is_active` when the offer has date settings configured.
Conditional: Returned together with `is_active` when the offer has date settings configured.
products Product[] conditional
Conditional: Included when the offer's products are part of the response.
is_paid boolean conditional
Conditional: Included when payment status is determined for the current viewer.

OfferIdentifier

id integer
title string

OfferSimple

id integer
title string
description string nullable
url string
Публічний URL для купівлі пропозиції
type_id integer
Ідентифікатор типу пропозиції
status string nullable
Ідентифікатор статусу пропозиції
Чи тарифікує підписку мерчант
Conditional: Included when product identity entries are loaded for the offer.
curators object[] conditional
Conditional: Included when curator entries are loaded for the offer.
is_paid boolean conditional
Conditional: Included when payment status is determined for the current viewer.

OfferDiscount

id integer
Фінальна ціна із застосованою знижкою
Тип обмеження знижки (enum-payload)
start_at datetime nullable
start_at_utc datetime nullable
start_timezone_id integer nullable
end_at datetime nullable
end_type string nullable
Як закінчується знижка (фіксована дата, після числа продажів тощо)
end_at_utc datetime nullable
end_timezone_id integer nullable
sales_limit integer nullable
Максимальна кількість продажів зі знижкою
sales integer
Скільки продажів зі знижкою вже відбулося
is_active boolean
is_available boolean
Чи діє знижка зараз (не закінчилась, не вичерпана)
created_at datetime
updated_at datetime
offer OfferIdentifier conditional
Conditional: Included when the parent offer is part of the response.
Короткі ідентифікаційні дані батьківської пропозиції

Замовлення

Order

id integer
type_id integer
Ідентифікатор типу замовлення
first_paid_at datetime nullable
paid_at datetime nullable
created_at datetime
updated_at datetime
products Product[] conditional
Conditional: Included when the order contains product information.
payments Payment[] conditional
Conditional: Included when the order has payment records.
paid_status integer nullable
Ідентифікатор статусу оплати
paid_status_title string nullable
Локалізована назва статусу оплати
order_stage OrderStage conditional
Conditional: Included when the order has a stage assigned.
Повна вартість замовлення з валютою
managers UserSimple[] conditional
Conditional: Included when the order has assigned managers.
offers Offer[] conditional
Conditional: Included when the order contains offer information.
utm UtmList conditional
Conditional: Included when UTM data is available for the order.

OrderFunnel

id integer
title string
Локалізована назва воронки
created_at datetime

OrderGroup

id integer
slug string
title string
Локалізована назва групи
order integer
Позиція групи всередині її воронки
created_at datetime

OrderStage

id integer
title string
Локалізована назва етапу
order_group OrderGroup conditional
Conditional: Included when the parent group is part of the response.
Conditional: Included when the parent funnel is part of the response.
created_at datetime

Платежі

Payment

id integer
status string
Ідентифікатор статусу оплати
status_title string
Локалізована назва статусу оплати
payment_type string nullable
Ідентифікатор типу оплати (разова, рекурентна тощо)
payment_type_title string nullable
Локалізована назва типу оплати
payment_form string nullable
Ідентифікатор форми оплати (онлайн, вручну тощо)
payment_form_title string nullable
Локалізована назва форми оплати
purchase_type string nullable
Ідентифікатор типу покупки
purchase_type_title string nullable
Локалізована назва типу покупки
Ціна з інформацією про валюту
paid_at datetime nullable
created_at datetime
updated_at datetime
Conditional: Included when payment transactions are part of the response.

Transaction

id integer
merchant_id integer nullable
payment_id integer
order_id integer nullable
payment_system_status string nullable
Сирий рядок статусу від платіжної системи
failure_reason string nullable
Причина невдачі транзакції, якщо застосовно
price number
currency_code string nullable
payer_account string nullable
Маскований ідентифікатор платника (останні цифри картки / handle гаманця)
card_mask string nullable
rrn string nullable
Retrieval Reference Number від банку
fee number nullable
Комісія платіжної системи
created_at datetime

Price

amount number
Сире значення суми
Сума, округлена за налаштуваннями округлення кабінету
Сума з підставленим символом / кодом валюти
Сума з підставленим ISO-кодом валюти

Currency

id integer
code string
ISO-код валюти
html_code string
Локалізоване HTML-представлення символу валюти
Локалізоване HTML-представлення буквеного коду валюти

Продукти

Product

id integer
productable_id integer
Ідентифікатор нижчележачої сутності (курс, info-unit тощо)
Поліморфний тип нижчележачої сутності (`course`, `info_unit` тощо)
title string
Локалізована назва productable-сутності
link string conditional
Conditional: Included when the underlying entity is part of the response.
Публічне посилання на productable-сутність

ProductIdentifier

id integer
Поліморфний тип нижчележачої сутності (`course`, `info_unit` тощо)
productable_id integer
name string
Локалізована назва нижчележачої сутності
link string
Публічне посилання на нижчележачу сутність
course_type_id Enum conditional
Conditional: Included when the underlying entity is a course; carries the course type enum.
Conditional: Included when course lesson identity payloads are loaded for the product.

ProductAggregatedSubscription

is_active boolean
Чи активний зараз доступ до продукту
is_paid boolean
Чи оплачена підписка (не пробна)
start_at datetime nullable
end_at datetime nullable
Ефективна дата закінчення доступу (обчислюється за всіма активними підписками)
offer_end_at datetime nullable
order_end_at datetime nullable
count_available_days integer nullable
Загальна кількість днів доступу контакту до продукту
count_left_days integer nullable
Залишилось днів доступу
Поточний стан (enum-payload)

ProductSubscription

id integer
creator_id integer nullable
user_id integer
product_id integer
order_id integer nullable
offer_id integer nullable
is_active boolean
start_at datetime nullable
order_end_at datetime nullable
end_at datetime nullable
Ефективна дата закінчення доступу для цієї підписки
paid_at datetime nullable
created_at datetime
updated_at datetime

UserProduct

id integer
productable_id integer
Поліморфний тип нижчележачої сутності
title string
image_url string nullable
URL превʼю-картинки productable-сутності
is_published boolean
Conditional: Included when subscription summary is part of the response.
Агрегована інформація про доступ (загальний is_active/start/end за всіма підписками)
Conditional: Included when individual subscription records are part of the response.
Окремі записи підписок (по одній на замовлення/пропозицію)

Email

EmailCampaign

id integer
title string
Назва розсилки; для системних розсилок фолбек на локалізовану підпис «Транзакційна»
state_id integer
Ідентифікатор стану розсилки
is_restricted boolean
True для вбудованих системних розсилок, які не можна редагувати
not_verified boolean
True, якщо у власника акаунту немає підтвердженого способу оплати / поповнення
is_system boolean
is_segment boolean
True, якщо розсилка націлена на динамічний сегмент
cabinet_id integer
user_id integer
subject string nullable
subsubject string nullable
Прехедер / прев'ю-текст, що відображається під темою листа
start_type string nullable
Ідентифікатор типу розкладу (immediate, scheduled, recurring тощо)
start_at_utc datetime nullable
start_at datetime nullable
timezone_id integer nullable
paused_at datetime nullable
rejected_at datetime nullable
finished_at datetime nullable
timezone Timezone nullable
Conditional: Included when the campaign's contact lists are loaded.
bounced_limit number
Поріг, вище якого частка bounce вважається проблемною
Поріг, вище якого частка скарг вважається проблемною
count_recipients integer conditional
Conditional: Included when the campaign statistic is loaded.
complaint_rate number conditional
Conditional: Included when the campaign statistic is loaded.
bounced_rate number conditional
Conditional: Included when the campaign statistic is loaded.
count_opened integer conditional
Conditional: Included when the campaign statistic is loaded.
count_clicks integer conditional
Conditional: Included when the campaign statistic is loaded.
percent_opened number conditional
Conditional: Included when the campaign statistic is loaded.
percent_clicks number conditional
Conditional: Included when the campaign statistic is loaded.
percent_completed number conditional
Conditional: Included when the campaign statistic is loaded.
distributor_id integer conditional
Conditional: Returned only for viewers with extended mailing access.
templatable_type string conditional
Conditional: Returned only for viewers with extended mailing access.
templatable_id integer conditional
Conditional: Returned only for viewers with extended mailing access.
template object conditional
Conditional: Returned only for viewers with extended mailing access when the templatable relation is loaded.
Дані email-шаблону (системний або кастомний)
distributor object conditional
Conditional: Returned only for viewers with extended mailing access when the distributor relation is loaded.
statistic object conditional
Conditional: Returned only for viewers with extended mailing access when the statistic relation is loaded.
Повний знімок статистики розсилки

EmailCampaignIdentifier

id integer
title string
Назва розсилки; для системних розсилок фолбек на локалізовану підпис

Візити

Visit

id integer
ip string nullable
landing_url string nullable
Повний URL приземлення (auth-хеш видалено)
landing_domain string nullable
landing_path string nullable
landing_params string nullable
Рядок query landing-URL без auth-хеша
referrer_url string nullable
referrer_domain string nullable
utm_source string nullable
utm_campaign string nullable
utm_medium string nullable
utm_term string nullable
utm_content string nullable
location string nullable
Розпізнана мітка локації (місто, країна)
Детальна розбивка за геолокацією
device VisitUserAgent conditional
Conditional: Included when user agent / device data is available for the visit.
Інформація про user agent / пристрій
created_at datetime

VisitLocation

Локалізований payload країни
state_name string nullable
Назва штату / регіону
city string nullable
full_location string
Шлях `city, state, country` через кому, порожні частини пропускаються

VisitUserAgent

user_agent string nullable
Сирий заголовок User-Agent, зафіксований на візиті
browser string nullable
browser_version string nullable
platform string nullable
Назва операційної системи
platform_version string nullable
Тип пристрою (enum-payload: desktop, mobile, tablet)
title string
Читаюче резюме user agent

UtmList

utm_source string[]
Унікальні значення utm_source за всіма візитами контакту
utm_campaign string[]
utm_medium string[]
utm_term string[]
utm_content string[]

Коментарі

CommentIdentifier

id integer
text string
Сирий текст коментаря
commentable_id integer
Ідентифікатор сутності, до якої прикріплено коментар
Поліморфний тип цільової сутності
commentable object conditional
Conditional: Included when the target entity is part of the response.
Короткий payload цільової сутності

Загальне

DateSetting

type string
Тип налаштування — `fixed`, `relative`, `recurring` тощо
duration_type_id integer nullable
Ідентифікатор одиниці тривалості (дні/тижні/місяці)
date_at datetime nullable
Фіксована дата в таймзоні кабінету
date_at_utc datetime nullable
Та сама дата, переведена в UTC
timezone_id integer nullable
timezone Timezone nullable
after_months integer nullable
Відносний зсув у місяцях (для relative-типів)
after_days integer nullable
specific_time string nullable
Конкретний час дня (HH:MM)
specific_day_of_week integer nullable
1 (понеділок) – 7 (неділя), якщо привʼязано до конкретного дня тижня
is_current_week boolean nullable
is_current_day boolean nullable

Timezone

id integer
name string
Ідентифікатор таймзони IANA
name_full string
Назва таймзони зі зміщенням UTC для відображення
value string
Рядок UTC-зміщення

Enum

id integer
Числове значення enum (в деяких місцях називається `value`)
slug string
Імʼя enum-кейса (стабільний рядковий ідентифікатор)
title string
Локалізований підпис enum у поточному `X-Language`

FileSimple

id integer
uuid string
Універсальний унікальний ідентифікатор файлу
name string
Внутрішнє збережене ім'я файлу
original_name string
Оригінальне ім'я файлу, завантаженого користувачем
url string nullable
Публічне посилання на файл (null, якщо сховище недоступне або у читача немає доступу)
thumbnails object nullable
Карта розмірів прев'ю на публічні посилання
extension string nullable
Розширення файлу без провідної крапки
type_id integer
Ідентифікатор типу файлу
mime_type string nullable

UserSimple

id integer
name string nullable
Повне імʼя користувача (імʼя + прізвище)
email string nullable
Email користувача (може бути приховано від не-власників)

CountrySimple

id integer
code string
ISO 3166-1 alpha-2 код країни
name string
Локалізована назва країни в поточному `X-Language`

Обгортки та пагінація

Success

success boolean

AffectedSubscriptions

ID видалених записів підписок
affected_orders integer[]
ID замовлень, у яких було порушено доступ (стали custom)
Розбивка за offer_id; кожне значення містить масиви `affected_subscriptions` і `affected_orders`. Порожній обʼєкт, якщо offers не передавалися.
Розбивка за product_id; та сама структура, що в `affected_by_offers`. Порожній обʼєкт, якщо product_id не передавався.

first string nullable
URL першої сторінки
last string nullable
URL останньої сторінки
prev string nullable
URL попередньої сторінки (null на першій)
next string nullable
URL наступної сторінки (null на останній)

PaginationMeta

current_page integer
from integer nullable
Індекс першого елемента на поточній сторінці (з 1)
last_page integer
Елементи навігації (prev / кнопки-номери сторінок / next) для відмалювання пагінатора
path string
Базовий шлях для побудови URL пагінації
per_page integer
to integer nullable
Індекс останнього елемента на поточній сторінці (з 1)
total integer
Загальна кількість елементів за всіма сторінками

url string nullable
URL посилання (null для поточної сторінки)
label string
Відображуваний підпис — номер сторінки, "« Previous", "Next »" тощо
active boolean
True для елемента, що представляє поточну сторінку