Введение
Это страница документации 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 (сейчас POST /contacts/:contact/rewards; другие будут отмечаться индивидуально) принимают опциональный header Idempotency-Key. Передайте уникальное значение один раз и переиспользуйте его на каждом ретрае той же логической операции — сервер «свернёт» повторы в один сайд-эффект и на каждый ретрай вернёт тот же ответ.
Эндпоинты, поддерживающие идемпотентность, помечены в этой документации плашкой: Идемпотентный
Контракт:
| Header | Поведение |
|---|---|
Idempotency-Key (request) |
Уникальная строка от клиента (1–255 символов). Подойдёт UUIDv4 или стабильный бизнес-ключ типа reward-for-quiz-attempt-4821. Пустой/отсутствующий header выключает идемпотентность для этого вызова. Клиенты, которые не могут передавать кастомные headers (form-based интеграции), могут передать то же значение как поле body/query idempotency_key — header имеет приоритет, если переданы оба. |
Idempotent-Replayed: true (response) |
Возвращается на второй и последующих вызовах с тем же ключом. Если видите этот header — сервер НЕ выполнял операцию повторно, body содержит тот же объект, что был создан при первом вызове (сущность перечитывается и сериализуется заново, поэтому отражает своё текущее состояние). Если эта сущность была к этому моменту удалена окончательно, body — это минимальное подтверждение с её типом и id. |
Область ключа — (кабинет, эндпоинт, ключ): тот же бизнес-ключ на другом эндпоинте или в другом кабинете считается отдельной операцией. Рекомендуем всё равно UUIDv4 — коллизии становятся статистически невозможны.
Базовая работа с 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/:contact', $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/:contact');
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' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get contact by ID
const url = 'https://api.kwiga.com/contacts/:contact';
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/:contact'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
response = requests.get(url, headers=headers)
result = response.json()
{
"method": "GET",
"url": "https://api.kwiga.com/contacts/:contact",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
Все запросы должны отправляться на домен:
https://api.kwiga.com
Для авторизации передаём API-токен в одном из вариантов:
в заголовках:
Token: {token}в GET/POST параметрах:
token={token}
Для идентификации кабинета, в котором происходят действия, обязательно передаём хеш-кабинета в одном из вариантов:
в заголовках:
Cabinet-Hash: {cabinet_hash}в GET/POST параметрах:
cabinet_hash={cabinet_hash}
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()
{
"method": "GET",
"url": "https://api.kwiga.com/contacts",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
# ---
# Paginated example
# ---
{
"method": "GET",
"url": "https://api.kwiga.com/contacts?page=1&per_page=15",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
# ---
# Filtered example
# ---
{
"method": "GET",
"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": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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": "« translation missing: ru.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: ru.pagination_next »",
"active": false
}
],
"path": "https://api.kwiga.com/contacts",
"per_page": 15,
"to": 2,
"total": 3
}
}
GET https://api.kwiga.com/contacts
URL Parameters
115asc, 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/:contact', $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/:contact');
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' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get contact by ID
const url = 'https://api.kwiga.com/contacts/:contact';
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/:contact'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
response = requests.get(url, headers=headers)
result = response.json()
{
"method": "GET",
"url": "https://api.kwiga.com/contacts/:contact",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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
Структура ответа
Создание контакта
Пример запроса:
<?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()
{
"method": "POST",
"url": "https://api.kwiga.com/contacts",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"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"
}
]
}
}
Пример ответа:
{
"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
falseenСтруктура ответа
Обновление контакта
Пример запроса:
<?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/:contact', $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/:contact');
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/:contact' \
--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/:contact';
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/:contact'
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()
{
"method": "PUT",
"url": "https://api.kwiga.com/contacts/:contact",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"first_name": "John",
"last_name": "Black",
"email": "bond123@example.com",
"phone": "+380931112233",
"tags": [
"test-tag"
]
}
}
Пример ответа:
{
"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
Структура ответа
Добавить покупку
Этот метод создаёт или находит контакт и добавляет ему покупку предложения
Пример запроса:
<?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()
{
"method": "POST",
"url": "https://api.kwiga.com/contacts/purchases",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"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"
}
]
}
}
Пример ответа:
{
"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",
"url": "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
falsefalsefalseenhttps://sample-school.kwiga.com/expert/payments/offers/edit/3858). Если не передан — запрос обращается к полю product_ids.
Если offer_id и product_ids отсутсвуют, то будет создан пустой заказ
trueСтруктура ответа
Теги
Добавление тегов контактам
Пример запроса:
<?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()
{
"method": "POST",
"url": "https://api.kwiga.com/contacts/tags",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"contacts": [
23698
],
"tags": [
"test-tag"
]
}
}
Пример ответа:
{
"success": true
}
POST https://api.kwiga.com/contacts/tags
Request
contact_ids. Сохранён ради обратной совместимости; в новых интеграциях используйте contact_ids.
Структура ответа
Удаление тегов контактов
Пример запроса:
<?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()
{
"method": "DELETE",
"url": "https://api.kwiga.com/contacts/tags",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"contacts": [
23698
],
"tags": [
"test-tag"
]
}
}
Пример ответа:
{
"success": true
}
DELETE https://api.kwiga.com/contacts/tags
Request
contact_ids. Сохранён ради обратной совместимости; в новых интеграциях используйте contact_ids.
Структура ответа
Продукты и подписки
Список продуктов контакта
Пример запроса:
<?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()
{
"method": "GET",
"url": "https://api.kwiga.com/contacts/:contact/products",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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()
{
"method": "DELETE",
"url": "https://api.kwiga.com/contacts/:contact/products/:product",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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()
{
"method": "DELETE",
"url": "https://api.kwiga.com/contacts/products",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"email": "user@example.com",
"product_id": 299,
"offers": [
421
]
}
}
Пример ответа:
{
"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
Структура ответа
Заморозить подписку контакта
Пример запроса:
<?php
// Freeze the subscription for 30 days
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.kwiga.com']);
$options = [
'headers' => [
'Accept' => 'application/json',
'Token' => '<Token>',
'Cabinet-Hash' => '<Cabinet-Hash>',
],
'json' => [
'count_frozen_days' => 30,
],
];
$response = $client->request('POST', '/contacts/:contact/products/:product/freeze', $options);
$result = json_decode($response->getBody());
?>
<?php
// Freeze the subscription for 30 days
$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/freeze');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$data = [
'count_frozen_days' => 30,
];
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/:contact/products/:product/freeze' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"count_frozen_days":30}'
// Freeze the subscription for 30 days
const url = 'https://api.kwiga.com/contacts/:contact/products/:product/freeze';
const options = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
},
body: JSON.stringify({
'count_frozen_days': 30
})
};
fetch(url, options)
.then(response => response.json())
.then(result => {
console.log(result);
})
.catch(error => {
console.error('Error:', error);
});
# Freeze the subscription for 30 days
import requests
url = 'https://api.kwiga.com/contacts/:contact/products/:product/freeze'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
data = {
'count_frozen_days': 30,
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
{
"method": "POST",
"url": "https://api.kwiga.com/contacts/:contact/products/:product/freeze",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"count_frozen_days": 30
}
}
Пример ответа:
{
"data": {
"id": 299,
"productable_id": 142,
"productable_type": "course",
"title": "JS Foundations",
"image_url": "https://cdn.kwiga.com/preview.jpg",
"url": "https://kwiga.com/courses/js-foundations",
"is_published": true,
"aggregated_subscription": {
"is_active": false,
"is_paid": true,
"start_at": "2026-06-05T00:00:00.000000Z",
"end_at": "2026-08-04T00:00:00.000000Z",
"offer_end_at": null,
"order_end_at": "2026-08-04T00:00:00.000000Z",
"frozen_at": "2026-05-20T10:00:00.000000Z",
"extended_at": null,
"count_available_days": 60,
"count_left_days": 60,
"state": {
"id": 4,
"name": "Frozen",
"title": "Frozen"
}
},
"subscriptions": [
{
"id": 4775,
"creator_id": 24457,
"user_id": 24457,
"product_id": 299,
"order_id": 2710,
"offer_id": 757,
"is_active": false,
"start_at": "2026-06-05T00:00:00.000000Z",
"order_end_at": "2026-08-04T00:00:00.000000Z",
"end_at": "2026-08-04T00:00:00.000000Z",
"frozen_at": "2026-05-20T10:00:00.000000Z",
"extended_at": null,
"paid_at": "2026-05-05T15:09:04.000000Z",
"created_at": "2026-05-05T15:09:04.000000Z",
"updated_at": "2026-05-06T12:42:11.000000Z"
}
]
}
}
POST https://api.kwiga.com/contacts/:contact/products/:product/freeze
Замораживает все активные подписки контакта на этом продукте на count_frozen_days календарных дней. Заморозка сдвигает start_at / end_at / order_end_at вперёд, делает подписку неактивной и уведомляет ученика. При разморозке (ручной или автоматической по окончании срока) start_at возвращается назад на основе данных заказа ученика, а не просто откатывается на ту же дельту.
URL Parameters
Структура ответа
Разморозить подписку контакта
Пример запроса:
<?php
// Unfreeze the subscription (no body)
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('POST', '/contacts/:contact/products/:product/unfreeze', $options);
$result = json_decode($response->getBody());
?>
<?php
// Unfreeze the subscription (no body)
$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/unfreeze');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$data = [
];
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/:contact/products/:product/unfreeze' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Unfreeze the subscription (no body)
const url = 'https://api.kwiga.com/contacts/:contact/products/:product/unfreeze';
const options = {
method: 'POST',
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);
});
# Unfreeze the subscription (no body)
import requests
url = 'https://api.kwiga.com/contacts/:contact/products/:product/unfreeze'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
response = requests.post(url, headers=headers)
result = response.json()
{
"method": "POST",
"url": "https://api.kwiga.com/contacts/:contact/products/:product/unfreeze",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
Пример ответа:
{
"data": {
"id": 299,
"productable_id": 142,
"productable_type": "course",
"title": "JS Foundations",
"image_url": "https://cdn.kwiga.com/preview.jpg",
"url": "https://kwiga.com/courses/js-foundations",
"is_published": true,
"aggregated_subscription": {
"is_active": false,
"is_paid": true,
"start_at": "2026-06-05T00:00:00.000000Z",
"end_at": "2026-08-04T00:00:00.000000Z",
"offer_end_at": null,
"order_end_at": "2026-08-04T00:00:00.000000Z",
"frozen_at": "2026-05-20T10:00:00.000000Z",
"extended_at": null,
"count_available_days": 60,
"count_left_days": 60,
"state": {
"id": 4,
"name": "Frozen",
"title": "Frozen"
}
},
"subscriptions": [
{
"id": 4775,
"creator_id": 24457,
"user_id": 24457,
"product_id": 299,
"order_id": 2710,
"offer_id": 757,
"is_active": false,
"start_at": "2026-06-05T00:00:00.000000Z",
"order_end_at": "2026-08-04T00:00:00.000000Z",
"end_at": "2026-08-04T00:00:00.000000Z",
"frozen_at": "2026-05-20T10:00:00.000000Z",
"extended_at": null,
"paid_at": "2026-05-05T15:09:04.000000Z",
"created_at": "2026-05-05T15:09:04.000000Z",
"updated_at": "2026-05-06T12:42:11.000000Z"
}
]
}
}
POST https://api.kwiga.com/contacts/:contact/products/:product/unfreeze
Размораживает все замороженные подписки контакта на этом продукте. Восстанавливает start_at, пересчитывает end_at / order_end_at (отнимает неиспользованный остаток заморозки), активирует доступ если он не истёк и уведомляет ученика. Тело пустое.
Структура ответа
Продлить подписку контакта
Пример запроса:
<?php
// Extend access by 14 days
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.kwiga.com']);
$options = [
'headers' => [
'Accept' => 'application/json',
'Token' => '<Token>',
'Cabinet-Hash' => '<Cabinet-Hash>',
],
'json' => [
'count_extend_days' => 14,
],
];
$response = $client->request('POST', '/contacts/:contact/products/:product/extend', $options);
$result = json_decode($response->getBody());
?>
<?php
// Extend access by 14 days
$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/extend');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$data = [
'count_extend_days' => 14,
];
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/:contact/products/:product/extend' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"count_extend_days":14}'
// Extend access by 14 days
const url = 'https://api.kwiga.com/contacts/:contact/products/:product/extend';
const options = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
},
body: JSON.stringify({
'count_extend_days': 14
})
};
fetch(url, options)
.then(response => response.json())
.then(result => {
console.log(result);
})
.catch(error => {
console.error('Error:', error);
});
# Extend access by 14 days
import requests
url = 'https://api.kwiga.com/contacts/:contact/products/:product/extend'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
data = {
'count_extend_days': 14,
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
{
"method": "POST",
"url": "https://api.kwiga.com/contacts/:contact/products/:product/extend",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"count_extend_days": 14
}
}
Пример ответа:
{
"data": {
"id": 299,
"productable_id": 142,
"productable_type": "course",
"title": "JS Foundations",
"image_url": "https://cdn.kwiga.com/preview.jpg",
"url": "https://kwiga.com/courses/js-foundations",
"is_published": true,
"aggregated_subscription": {
"is_active": false,
"is_paid": true,
"start_at": "2026-06-05T00:00:00.000000Z",
"end_at": "2026-08-04T00:00:00.000000Z",
"offer_end_at": null,
"order_end_at": "2026-08-04T00:00:00.000000Z",
"frozen_at": "2026-05-20T10:00:00.000000Z",
"extended_at": null,
"count_available_days": 60,
"count_left_days": 60,
"state": {
"id": 4,
"name": "Frozen",
"title": "Frozen"
}
},
"subscriptions": [
{
"id": 4775,
"creator_id": 24457,
"user_id": 24457,
"product_id": 299,
"order_id": 2710,
"offer_id": 757,
"is_active": false,
"start_at": "2026-06-05T00:00:00.000000Z",
"order_end_at": "2026-08-04T00:00:00.000000Z",
"end_at": "2026-08-04T00:00:00.000000Z",
"frozen_at": "2026-05-20T10:00:00.000000Z",
"extended_at": null,
"paid_at": "2026-05-05T15:09:04.000000Z",
"created_at": "2026-05-05T15:09:04.000000Z",
"updated_at": "2026-05-06T12:42:11.000000Z"
}
]
}
}
POST https://api.kwiga.com/contacts/:contact/products/:product/extend
Добавляет count_extend_days календарных дней к end_at / order_end_at всех подписок контакта на этом продукте. Та же ручка используется в CRM-автоматизациях для реактивации просроченных подписок.
URL Parameters
Структура ответа
Изменить дату окончания подписки
Пример запроса:
<?php
// Set the subscription end to the given date in the chosen timezone
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.kwiga.com']);
$options = [
'headers' => [
'Accept' => 'application/json',
'Token' => '<Token>',
'Cabinet-Hash' => '<Cabinet-Hash>',
],
'json' => [
'end_at' => '2027-01-01 23:59:59',
'timezone_id' => 1,
],
];
$response = $client->request('PUT', '/contacts/:contact/products/:product/end-date', $options);
$result = json_decode($response->getBody());
?>
<?php
// Set the subscription end to the given date in the chosen timezone
$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/end-date');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
$data = [
'end_at' => '2027-01-01 23:59:59',
'timezone_id' => 1,
];
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/:contact/products/:product/end-date' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"end_at":"2027-01-01 23:59:59","timezone_id":1}'
// Set the subscription end to the given date in the chosen timezone
const url = 'https://api.kwiga.com/contacts/:contact/products/:product/end-date';
const options = {
method: 'PUT',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
},
body: JSON.stringify({
'end_at': '2027-01-01 23:59:59',
'timezone_id': 1
})
};
fetch(url, options)
.then(response => response.json())
.then(result => {
console.log(result);
})
.catch(error => {
console.error('Error:', error);
});
# Set the subscription end to the given date in the chosen timezone
import requests
url = 'https://api.kwiga.com/contacts/:contact/products/:product/end-date'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
data = {
'end_at': '2027-01-01 23:59:59',
'timezone_id': 1,
}
response = requests.put(url, headers=headers, json=data)
result = response.json()
{
"method": "PUT",
"url": "https://api.kwiga.com/contacts/:contact/products/:product/end-date",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"end_at": "2027-01-01 23:59:59",
"timezone_id": 1
}
}
Пример ответа:
{
"data": {
"id": 299,
"productable_id": 142,
"productable_type": "course",
"title": "JS Foundations",
"image_url": "https://cdn.kwiga.com/preview.jpg",
"url": "https://kwiga.com/courses/js-foundations",
"is_published": true,
"aggregated_subscription": {
"is_active": false,
"is_paid": true,
"start_at": "2026-06-05T00:00:00.000000Z",
"end_at": "2026-08-04T00:00:00.000000Z",
"offer_end_at": null,
"order_end_at": "2026-08-04T00:00:00.000000Z",
"frozen_at": "2026-05-20T10:00:00.000000Z",
"extended_at": null,
"count_available_days": 60,
"count_left_days": 60,
"state": {
"id": 4,
"name": "Frozen",
"title": "Frozen"
}
},
"subscriptions": [
{
"id": 4775,
"creator_id": 24457,
"user_id": 24457,
"product_id": 299,
"order_id": 2710,
"offer_id": 757,
"is_active": false,
"start_at": "2026-06-05T00:00:00.000000Z",
"order_end_at": "2026-08-04T00:00:00.000000Z",
"end_at": "2026-08-04T00:00:00.000000Z",
"frozen_at": "2026-05-20T10:00:00.000000Z",
"extended_at": null,
"paid_at": "2026-05-05T15:09:04.000000Z",
"created_at": "2026-05-05T15:09:04.000000Z",
"updated_at": "2026-05-06T12:42:11.000000Z"
}
]
}
}
PUT https://api.kwiga.com/contacts/:contact/products/:product/end-date
Перезаписывает end_at (и order_end_at, если она есть) явной датой. Дата интерпретируется в таймзоне timezone_id (см. эндпоинт списка таймзон); если timezone_id не указан, end_at трактуется как UTC.
URL Parameters
timezone_id.
end_at трактуется как UTC.
Структура ответа
Баллы (награды)
Журнал баллов контакта
Пример запроса:
<?php
// List rewards (default ordering)
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/rewards', $options);
$result = json_decode($response->getBody());
?>
# ---
# Filtered example
# ---
<?php
// Only accruals from quiz-passed and manual reasons, scoped to two 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/rewards?filters[accrual_type]=accrued&filters[reason_types]=1,6&filters[product_ids]=10,11&per_page=50', $options);
$result = json_decode($response->getBody());
?>
<?php
// List rewards (default ordering)
$headers = [
'Accept: application/json',
'Token: <Token>',
'Cabinet-Hash: <Cabinet-Hash>',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/:contact/rewards');
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
// Only accruals from quiz-passed and manual reasons, scoped to two 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/rewards?filters[accrual_type]=accrued&filters[reason_types]=1,6&filters[product_ids]=10,11&per_page=50');
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/rewards' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
# ---
# Filtered example
# ---
curl --location --request GET 'https://api.kwiga.com/contacts/:contact/rewards?filters[accrual_type]=accrued&filters[reason_types]=1,6&filters[product_ids]=10,11&per_page=50' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// List rewards (default ordering)
const url = 'https://api.kwiga.com/contacts/:contact/rewards';
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
# ---
// Only accruals from quiz-passed and manual reasons, scoped to two products
const url = 'https://api.kwiga.com/contacts/:contact/rewards?filters[accrual_type]=accrued&filters[reason_types]=1,6&filters[product_ids]=10,11&per_page=50';
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);
});
# List rewards (default ordering)
import requests
url = 'https://api.kwiga.com/contacts/:contact/rewards'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
response = requests.get(url, headers=headers)
result = response.json()
# ---
# Filtered example
# ---
# Only accruals from quiz-passed and manual reasons, scoped to two products
import requests
url = 'https://api.kwiga.com/contacts/:contact/rewards?filters[accrual_type]=accrued&filters[reason_types]=1,6&filters[product_ids]=10,11&per_page=50'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
response = requests.get(url, headers=headers)
result = response.json()
{
"method": "GET",
"url": "https://api.kwiga.com/contacts/:contact/rewards",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
# ---
# Filtered example
# ---
{
"method": "GET",
"url": "https://api.kwiga.com/contacts/:contact/rewards?filters[accrual_type]=accrued&filters[reason_types]=1,6&filters[product_ids]=10,11&per_page=50",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
Пример ответа:
{
"data": [
{
"id": 9821,
"points": 50,
"accrual_type": {
"id": "accrued",
"slug": "Plus",
"title": "Accrued"
},
"reason_type": {
"id": 6,
"slug": "Manual",
"title": "Manual"
},
"event": null,
"event_name": null,
"eventable_type": null,
"eventable_id": null,
"event_comment": null,
"manual_comment": "Bonus for active chat participation",
"is_visible_to_student": true,
"message": "Manual points accrual: Bonus for active chat participation",
"product": null,
"creator": {
"id": 17,
"name": "Alice Curator",
"email": "alice@kwiga.com"
},
"created_at": "2026-05-24T11:14:51.000000Z"
},
{
"id": 9820,
"points": 25,
"accrual_type": {
"id": "accrued",
"slug": "Plus",
"title": "Accrued"
},
"reason_type": {
"id": 1,
"slug": "QuizPassed",
"title": "Quiz passed"
},
"event": "quiz.passed",
"event_name": "Quiz passed",
"eventable_type": "quiz_attempt",
"eventable_id": 4821,
"event_comment": null,
"manual_comment": null,
"is_visible_to_student": null,
"message": "Quiz Module 3 final test in lesson Closures & scope -> Attempt",
"product": {
"id": 431,
"productable_type": "course",
"productable_id": 226,
"name": "JS Foundations",
"url": "https://lm4.kwiga.com/courses/js-foundations"
},
"creator": null,
"created_at": "2026-05-23T11:14:51.000000Z"
},
{
"id": 9810,
"points": -30,
"accrual_type": {
"id": "deducted",
"slug": "Minus",
"title": "Deducted"
},
"reason_type": {
"id": 6,
"slug": "Manual",
"title": "Manual"
},
"event": null,
"event_name": null,
"eventable_type": null,
"eventable_id": null,
"event_comment": null,
"manual_comment": null,
"is_visible_to_student": null,
"message": "Manual points accrual",
"product": null,
"creator": {
"id": 17,
"name": "Alice Curator",
"email": "alice@kwiga.com"
},
"created_at": "2026-05-22T09:00:00.000000Z"
}
],
"links": {
"first": "https://api.kwiga.com/contacts/142/rewards?page=1",
"last": "https://api.kwiga.com/contacts/142/rewards?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "https://api.kwiga.com/contacts/142/rewards",
"per_page": 15,
"to": 3,
"total": 3
},
"sum_points": 45,
"sum_accrued_points": 75,
"sum_deducted_points": -30
}
GET https://api.kwiga.com/contacts/:contact/rewards
Возвращает журнал начислений и списаний баллов контакта — по квизам, заказам, подаркам, автоматизациям и ручным действиям кураторов. На верхнем уровне ответа также возвращаются суммы sum_points, sum_accrued_points, sum_deducted_points по текущему фильтру.
URL Parameters
151Структура ответа
Ручное начисление/списание баллов контакту Идемпотентный
Пример запроса:
<?php
// Accrue 50 points for finishing a milestone, unbound from any product
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.kwiga.com']);
$options = [
'headers' => [
'Accept' => 'application/json',
'Token' => '<Token>',
'Cabinet-Hash' => '<Cabinet-Hash>',
],
'json' => [
'points' => 50,
],
];
$response = $client->request('POST', '/contacts/:contact/rewards', $options);
$result = json_decode($response->getBody());
?>
# ---
# Accrue_with_product example
# ---
<?php
// Accrue 100 points scoped to product id 10
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.kwiga.com']);
$options = [
'headers' => [
'Accept' => 'application/json',
'Token' => '<Token>',
'Cabinet-Hash' => '<Cabinet-Hash>',
],
'json' => [
'points' => 100,
'product_id' => 10,
],
];
$response = $client->request('POST', '/contacts/:contact/rewards', $options);
$result = json_decode($response->getBody());
?>
# ---
# With_comment example
# ---
<?php
// Accrue 50 points with a curator comment that the student also sees in their journal
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.kwiga.com']);
$options = [
'headers' => [
'Accept' => 'application/json',
'Token' => '<Token>',
'Cabinet-Hash' => '<Cabinet-Hash>',
],
'json' => [
'points' => 50,
'comment' => 'Bonus for active chat participation',
'is_visible_to_student' => true,
],
];
$response = $client->request('POST', '/contacts/:contact/rewards', $options);
$result = json_decode($response->getBody());
?>
# ---
# Idempotent_accrual example
# ---
<?php
// Safely retry the same accrual — passing Idempotency-Key collapses replays to a single FlowReward
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.kwiga.com']);
$options = [
'headers' => [
'Accept' => 'application/json',
'Token' => '<Token>',
'Cabinet-Hash' => '<Cabinet-Hash>',
'Idempotency-Key' => 'reward-for-quiz-attempt-4821',
],
'json' => [
'points' => 25,
],
];
$response = $client->request('POST', '/contacts/:contact/rewards', $options);
$result = json_decode($response->getBody());
?>
# ---
# Deduct example
# ---
<?php
// Deduct 30 points
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.kwiga.com']);
$options = [
'headers' => [
'Accept' => 'application/json',
'Token' => '<Token>',
'Cabinet-Hash' => '<Cabinet-Hash>',
],
'json' => [
'points' => -30,
],
];
$response = $client->request('POST', '/contacts/:contact/rewards', $options);
$result = json_decode($response->getBody());
?>
<?php
// Accrue 50 points for finishing a milestone, unbound from any 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/rewards');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$data = [
'points' => 50,
];
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response);
?>
# ---
# Accrue_with_product example
# ---
<?php
// Accrue 100 points scoped to product id 10
$headers = [
'Accept: application/json',
'Token: <Token>',
'Cabinet-Hash: <Cabinet-Hash>',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/:contact/rewards');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$data = [
'points' => 100,
'product_id' => 10,
];
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response);
?>
# ---
# With_comment example
# ---
<?php
// Accrue 50 points with a curator comment that the student also sees in their journal
$headers = [
'Accept: application/json',
'Token: <Token>',
'Cabinet-Hash: <Cabinet-Hash>',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/:contact/rewards');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$data = [
'points' => 50,
'comment' => 'Bonus for active chat participation',
'is_visible_to_student' => true,
];
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response);
?>
# ---
# Idempotent_accrual example
# ---
<?php
// Safely retry the same accrual — passing Idempotency-Key collapses replays to a single FlowReward
$headers = [
'Accept: application/json',
'Token: <Token>',
'Cabinet-Hash: <Cabinet-Hash>',
'Idempotency-Key: reward-for-quiz-attempt-4821',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/:contact/rewards');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$data = [
'points' => 25,
];
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response);
?>
# ---
# Deduct example
# ---
<?php
// Deduct 30 points
$headers = [
'Accept: application/json',
'Token: <Token>',
'Cabinet-Hash: <Cabinet-Hash>',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/contacts/:contact/rewards');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
$data = [
'points' => -30,
];
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/:contact/rewards' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"points":50}'
# ---
# Accrue_with_product example
# ---
curl --location --request POST 'https://api.kwiga.com/contacts/:contact/rewards' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"points":100,"product_id":10}'
# ---
# With_comment example
# ---
curl --location --request POST 'https://api.kwiga.com/contacts/:contact/rewards' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"points":50,"comment":"Bonus for active chat participation","is_visible_to_student":true}'
# ---
# Idempotent_accrual example
# ---
curl --location --request POST 'https://api.kwiga.com/contacts/:contact/rewards' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--header 'Idempotency-Key: reward-for-quiz-attempt-4821' \
--data-raw '{"points":25}'
# ---
# Deduct example
# ---
curl --location --request POST 'https://api.kwiga.com/contacts/:contact/rewards' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>' \
--data-raw '{"points":-30}'
// Accrue 50 points for finishing a milestone, unbound from any product
const url = 'https://api.kwiga.com/contacts/:contact/rewards';
const options = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
},
body: JSON.stringify({
'points': 50
})
};
fetch(url, options)
.then(response => response.json())
.then(result => {
console.log(result);
})
.catch(error => {
console.error('Error:', error);
});
# ---
# Accrue_with_product example
# ---
// Accrue 100 points scoped to product id 10
const url = 'https://api.kwiga.com/contacts/:contact/rewards';
const options = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
},
body: JSON.stringify({
'points': 100,
'product_id': 10
})
};
fetch(url, options)
.then(response => response.json())
.then(result => {
console.log(result);
})
.catch(error => {
console.error('Error:', error);
});
# ---
# With_comment example
# ---
// Accrue 50 points with a curator comment that the student also sees in their journal
const url = 'https://api.kwiga.com/contacts/:contact/rewards';
const options = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
},
body: JSON.stringify({
'points': 50,
'comment': 'Bonus for active chat participation',
'is_visible_to_student': true
})
};
fetch(url, options)
.then(response => response.json())
.then(result => {
console.log(result);
})
.catch(error => {
console.error('Error:', error);
});
# ---
# Idempotent_accrual example
# ---
// Safely retry the same accrual — passing Idempotency-Key collapses replays to a single FlowReward
const url = 'https://api.kwiga.com/contacts/:contact/rewards';
const options = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
'Idempotency-Key': 'reward-for-quiz-attempt-4821',
},
body: JSON.stringify({
'points': 25
})
};
fetch(url, options)
.then(response => response.json())
.then(result => {
console.log(result);
})
.catch(error => {
console.error('Error:', error);
});
# ---
# Deduct example
# ---
// Deduct 30 points
const url = 'https://api.kwiga.com/contacts/:contact/rewards';
const options = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
},
body: JSON.stringify({
'points': -30
})
};
fetch(url, options)
.then(response => response.json())
.then(result => {
console.log(result);
})
.catch(error => {
console.error('Error:', error);
});
# Accrue 50 points for finishing a milestone, unbound from any product
import requests
url = 'https://api.kwiga.com/contacts/:contact/rewards'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
data = {
'points': 50,
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
# ---
# Accrue_with_product example
# ---
# Accrue 100 points scoped to product id 10
import requests
url = 'https://api.kwiga.com/contacts/:contact/rewards'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
data = {
'points': 100,
'product_id': 10,
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
# ---
# With_comment example
# ---
# Accrue 50 points with a curator comment that the student also sees in their journal
import requests
url = 'https://api.kwiga.com/contacts/:contact/rewards'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
data = {
'points': 50,
'comment': 'Bonus for active chat participation',
'is_visible_to_student': true,
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
# ---
# Idempotent_accrual example
# ---
# Safely retry the same accrual — passing Idempotency-Key collapses replays to a single FlowReward
import requests
url = 'https://api.kwiga.com/contacts/:contact/rewards'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
'Idempotency-Key': 'reward-for-quiz-attempt-4821',
}
data = {
'points': 25,
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
# ---
# Deduct example
# ---
# Deduct 30 points
import requests
url = 'https://api.kwiga.com/contacts/:contact/rewards'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
data = {
'points': -30,
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
{
"method": "POST",
"url": "https://api.kwiga.com/contacts/:contact/rewards",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"points": 50
}
}
# ---
# Accrue_with_product example
# ---
{
"method": "POST",
"url": "https://api.kwiga.com/contacts/:contact/rewards",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"points": 100,
"product_id": 10
}
}
# ---
# With_comment example
# ---
{
"method": "POST",
"url": "https://api.kwiga.com/contacts/:contact/rewards",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"points": 50,
"comment": "Bonus for active chat participation",
"is_visible_to_student": true
}
}
# ---
# Idempotent_accrual example
# ---
{
"method": "POST",
"url": "https://api.kwiga.com/contacts/:contact/rewards",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Idempotency-Key": "reward-for-quiz-attempt-4821",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"points": 25
}
}
# ---
# Deduct example
# ---
{
"method": "POST",
"url": "https://api.kwiga.com/contacts/:contact/rewards",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"points": -30
}
}
Пример ответа:
{
"data": {
"id": 9822,
"points": 50,
"accrual_type": {
"id": "accrued",
"slug": "Plus",
"title": "Accrued"
},
"reason_type": {
"id": 6,
"slug": "Manual",
"title": "Manual"
},
"event": null,
"event_name": null,
"eventable_type": null,
"eventable_id": null,
"event_comment": null,
"manual_comment": "Bonus for active chat participation",
"is_visible_to_student": true,
"message": "Manual points accrual: Bonus for active chat participation",
"product": null,
"creator": {
"id": 17,
"name": "Alice Curator",
"email": "alice@kwiga.com"
},
"created_at": "2026-05-25T14:30:00.000000Z"
}
}
POST https://api.kwiga.com/contacts/:contact/rewards
Добавляет ручную запись в журнал баллов контакта. Положительное points — начисление, отрицательное — списание. Опциональный product_id привязывает запись к конкретному продукту; иначе она «кабинет-уровневая». Reason type всегда Manual; в качестве куратора фиксируется текущий API-пользователь.
URL Parameters
message ответа. Ученик увидит комментарий в своём журнале баллов только если is_visible_to_student=true.
falseСтруктура ответа
Продукты
Список продуктов кабинета
Пример запроса:
<?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()
{
"method": "GET",
"url": "https://api.kwiga.com/products",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
# ---
# Paginated example
# ---
{
"method": "GET",
"url": "https://api.kwiga.com/products?per_page=20&page=1&sort_by=asc",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
Пример ответа:
{
"data": [
{
"id": 299,
"productable_id": 142,
"productable_type": "course",
"title": "Sample Course Title",
"url": "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
asc, descDefault: desc151Структура ответа
Курсы
Список курсов кабинета
Пример запроса:
<?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()
{
"method": "GET",
"url": "https://api.kwiga.com/courses",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
# ---
# With_params example
# ---
{
"method": "GET",
"url": "https://api.kwiga.com/courses?with[]=offers&with[]=description&with[]=program&per_page=15&page=1",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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"
},
"url": "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": "« Previous",
"active": false
},
{
"url": "http://api.kwiga.local/courses?page=1",
"label": "1",
"active": true
},
{
"url": null,
"label": "Next »",
"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
offers, description, programasc, descDefault: desc151Структура ответа
Список участников курса
Пример запроса:
<?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()
{
"method": "GET",
"url": "https://api.kwiga.com/courses/:course/users",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
# ---
# Filtered example
# ---
{
"method": "GET",
"url": "https://api.kwiga.com/courses/:course/users?progress_general_from=50&progress_general_to=100&per_page=20",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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",
"url": "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",
"url": "http://test.local/courses/Pm8CEofJ/3",
"module": {
"id": 7,
"course_id": 20,
"number": 1,
"title": "Module title"
}
},
"last_activity_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": "« Previous",
"active": false
},
{
"url": "http://api.kwiga.local/courses/20/users?page=1",
"label": "1",
"active": true
},
{
"url": null,
"label": "Next »",
"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
emails / contact_ids / user_id / user_ids в единый фильтр аудитории (union).
emails / contact_id / user_id / user_ids в единый фильтр аудитории (union).
emails / contact_id / contact_ids / user_ids в единый фильтр аудитории (union).
emails / contact_id / contact_ids / user_id в единый фильтр аудитории (union).
contact_id / contact_ids / user_id / user_ids в единый фильтр аудитории (union).
151Необязательный список расширений ответа через запятую. Каждый токен подключает одну секцию ответа — клиент платит только за то, что попросил.
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-узлов.
Структура ответа
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_progress→ индексируйте поlesson_idmodule_progress→ индексируйте поmodule_idquiz_progress→ индексируйте по паре(course_lesson_id, quiz_id), потому что один и тот же квиз может быть привязан к нескольким урокам
Про имена: записи прогресса используют lesson_id/module_id/course_lesson_id,
а узлы программы — course_nodeble_id. Это одно и то же значение,
просто в разных частях ответа — см. шаг 2.
2. Обойдите course_program и для каждого узла возьмите нужную запись.
У каждого узла есть course_nodeble_type + course_nodeble_id.
Используйте course_nodeble_id как ключ поиска:
- узел
course_module→module_progress[node.course_nodeble_id] - узел
course_lesson→lesson_progress[node.course_nodeble_id] - узел
info_section→ у секции своего прогресса нет. Пройдитесь поnode.quizzesи для каждого квиза возьмитеquiz_progress[(parent_lesson.course_nodeble_id, quiz.id)], гдеparent_lesson— ближайший родительский узелcourse_lesson.
Если поиск ничего не вернул — у ученика ещё нет прогресса по этому узлу, отрисуйте пустое состояние. Программа курса одинакова для всех учеников страницы, поэтому её безопасно построить один раз и переиспользовать между строками.
Попытки прохождения квизов
Список попыток в кабинете
Пример запроса:
<?php
// List quiz attempts (defaults — newest first by status_updated_at)
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', '/quiz-attempts', $options);
$result = json_decode($response->getBody());
?>
# ---
# Filtered example
# ---
<?php
// Filtered list — pending check & need rework, scoped to two 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', '/quiz-attempts?filters[practice_statuses]=3,6&filters[product_ids]=10,11&sort_by=last_activity_at&sort_dir=desc&per_page=50', $options);
$result = json_decode($response->getBody());
?>
<?php
// List quiz attempts (defaults — newest first by status_updated_at)
$headers = [
'Accept: application/json',
'Token: <Token>',
'Cabinet-Hash: <Cabinet-Hash>',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/quiz-attempts');
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
// Filtered list — pending check & need rework, scoped to two products
$headers = [
'Accept: application/json',
'Token: <Token>',
'Cabinet-Hash: <Cabinet-Hash>',
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.kwiga.com/quiz-attempts?filters[practice_statuses]=3,6&filters[product_ids]=10,11&sort_by=last_activity_at&sort_dir=desc&per_page=50');
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/quiz-attempts' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
# ---
# Filtered example
# ---
curl --location --request GET 'https://api.kwiga.com/quiz-attempts?filters[practice_statuses]=3,6&filters[product_ids]=10,11&sort_by=last_activity_at&sort_dir=desc&per_page=50' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// List quiz attempts (defaults — newest first by status_updated_at)
const url = 'https://api.kwiga.com/quiz-attempts';
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
# ---
// Filtered list — pending check & need rework, scoped to two products
const url = 'https://api.kwiga.com/quiz-attempts?filters[practice_statuses]=3,6&filters[product_ids]=10,11&sort_by=last_activity_at&sort_dir=desc&per_page=50';
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);
});
# List quiz attempts (defaults — newest first by status_updated_at)
import requests
url = 'https://api.kwiga.com/quiz-attempts'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
response = requests.get(url, headers=headers)
result = response.json()
# ---
# Filtered example
# ---
# Filtered list — pending check & need rework, scoped to two products
import requests
url = 'https://api.kwiga.com/quiz-attempts?filters[practice_statuses]=3,6&filters[product_ids]=10,11&sort_by=last_activity_at&sort_dir=desc&per_page=50'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
response = requests.get(url, headers=headers)
result = response.json()
{
"method": "GET",
"url": "https://api.kwiga.com/quiz-attempts",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
# ---
# Filtered example
# ---
{
"method": "GET",
"url": "https://api.kwiga.com/quiz-attempts?filters[practice_statuses]=3,6&filters[product_ids]=10,11&sort_by=last_activity_at&sort_dir=desc&per_page=50",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
Пример ответа:
{
"data": [
{
"id": 4821,
"root_id": 4810,
"previous_id": 4815,
"number_version": 3,
"user_id": 712,
"product_id": 431,
"quiz_id": 88,
"course_id": 226,
"course_lesson_id": 504,
"lesson_section": {
"id": 88,
"name": "Knowledge check",
"order": 3,
"url": "https://lm4.kwiga.com/courses/js-foundations/3/lessons/504",
"crm_url": "https://lm4.kwiga.com/expert/courses/js-foundations/3/lessons/504/sections/3"
},
"status": {
"id": 6,
"slug": "PendingCheck",
"title": "Pending review"
},
"scores": 12.5,
"scores_max": 15,
"count_questions": 10,
"count_questions_correct": 8,
"count_questions_incorrect": 2,
"is_force_approved": false,
"is_read": false,
"started_at": "2026-05-23T11:02:14.000000Z",
"last_activity_at": "2026-05-23T11:14:51.000000Z",
"finished_at": "2026-05-23T11:14:51.000000Z",
"deadline_at": null,
"status_updated_at": "2026-05-23T11:14:51.000000Z",
"checked_at": null,
"commented_at": null,
"canceled_at": null,
"passed_time_in_seconds": 757,
"crm_url": "https://lm4.kwiga.com/expert/practices?attempt_id=4821",
"user": {
"id": 712,
"name": "Alice Student",
"email": "alice@example.com"
},
"quiz": {
"id": 88,
"name": "Module 3 final test"
},
"course": {
"id": 226,
"product_id": 431,
"type": {
"id": 1,
"name": "Course",
"type": "course"
},
"title": "JS Foundations",
"slug": "js-foundations",
"url": "http://test.local/courses/js-foundations",
"status": {
"id": 3,
"name": "Published"
}
},
"lesson": {
"id": 504,
"title": "Closures & scope",
"course": {
"id": 226,
"product_id": 431,
"type_id": 1,
"title": "JS Foundations",
"url": "http://test.local/courses/js-foundations"
},
"module": {
"id": 30,
"course_id": 226,
"number": 3,
"title": "Functions in depth"
}
},
"product": {
"id": 431,
"productable_type": "course",
"productable_id": 226,
"name": "JS Foundations",
"url": "http://test.local/courses/js-foundations"
}
}
],
"links": {
"first": "https://api.kwiga.com/quiz-attempts?page=1",
"last": "https://api.kwiga.com/quiz-attempts?page=4",
"prev": null,
"next": "https://api.kwiga.com/quiz-attempts?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 4,
"path": "https://api.kwiga.com/quiz-attempts",
"per_page": 15,
"to": 15,
"total": 58,
"links": [
{ "url": null, "label": "« Previous", "active": false },
{ "url": "https://api.kwiga.com/quiz-attempts?page=1", "label": "1", "active": true },
{ "url": "https://api.kwiga.com/quiz-attempts?page=2", "label": "2", "active": false },
{ "url": "https://api.kwiga.com/quiz-attempts?page=2", "label": "Next »", "active": false }
]
},
"attempts_unread_count": 12
}
GET https://api.kwiga.com/quiz-attempts
Возвращает пагинированный список попыток учеников по квизам,
доступных авторизованному куратору во всём кабинете (без привязки
к продукту в URL — передайте параметр products, чтобы
сузить выборку). По умолчанию 15 элементов на страницу, максимум 250.
Поле attempts_unread_count на верхнем уровне показывает
количество непрочитанных попыток с теми же фильтрами — удобно
выводить как «бейдж» новых попыток.
URL Parameters
151last_activity_atPossible values: last_activity_at, status_updated_at, finished_at, statusDefault: last_activity_atdescPossible values: asc, descDefault: descСтруктура ответа
POST-алиас
POST https://api.kwiga.com/quiz-attempts/query
Функциональный алиас для GET-эндпоинта выше. Принимает те же параметры в теле запроса вместо query-string — пригодится, когда список фильтров слишком большой для URL (или просто удобнее собирать JSON на клиенте). Body имеет приоритет над query-string, форма ответа идентична.
Предложения
Получение списка предложений
Пример запроса:
<?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()
{
"method": "GET",
"url": "https://api.kwiga.com/offers?product_id=130",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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",
"url": "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",
"url": "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": "« Previous",
"active": false
},
{
"url": "http://api.kwiga.local/offers?page=1",
"label": "1",
"active": true
},
{
"url": null,
"label": "Next »",
"active": false
}
],
"path": "http://api.kwiga.local/offers",
"per_page": 15,
"to": 1,
"total": 2
}
}
GET https://api.kwiga.com/offers
URL Parameters
Структура ответа
Получение предложения
Пример запроса:
<?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/:offer', $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/:offer');
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/:offer' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get offer by ID
const url = 'https://api.kwiga.com/offers/:offer';
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/:offer'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
response = requests.get(url, headers=headers)
result = response.json()
{
"method": "GET",
"url": "https://api.kwiga.com/offers/:offer",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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()
{
"method": "GET",
"url": "https://api.kwiga.com/mailing/contact-lists",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
# ---
# Paginated example
# ---
{
"method": "GET",
"url": "https://api.kwiga.com/mailing/contact-lists?page=1&per_page=15",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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": "« translation missing: ru.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: ru.pagination_next »",
"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
Структура ответа
Получение списка контактов
Пример запроса:
<?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/:list', $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/:list');
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/:list' \
--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/:list';
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/:list'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
response = requests.get(url, headers=headers)
result = response.json()
{
"method": "GET",
"url": "https://api.kwiga.com/mailing/contact-lists/:list",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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()
{
"method": "POST",
"url": "https://api.kwiga.com/mailing/contact-lists/",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"title": "Название группы",
"description": "описание"
}
}
Пример ответа:
{
"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
Структура ответа
Добавление контактов в список
Пример запроса:
<?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()
{
"method": "POST",
"url": "https://api.kwiga.com/mailing/contact-lists/bulk-contacts",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"contacts[]": 2,
"contact_lists[]": 1
}
}
Пример ответа:
{
"success": true
}
POST https://api.kwiga.com/mailing/contact-lists/bulk-contacts
URL Parameters
Структура ответа
Продажи. Купоны
Список купонов
Пример запроса:
<?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()
{
"method": "GET",
"url": "https://api.kwiga.com/coupons",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json"
}
}
# ---
# Filtered example
# ---
{
"method": "GET",
"url": "https://api.kwiga.com/coupons?filters[date_from]=2022-04-15&filters[date_to]=2022-04-27",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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
Структура ответа
Получение купона
Пример запроса:
<?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/:coupon', $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/:coupon');
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/:coupon' \
--header 'Content-Type: application/json' \
--header 'Token: <Token>' \
--header 'Cabinet-Hash: <Cabinet-Hash>'
// Get coupon by ID
const url = 'https://api.kwiga.com/coupons/:coupon';
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/:coupon'
headers = {
'Accept': 'application/json',
'Token': '<Token>',
'Cabinet-Hash': '<Cabinet-Hash>',
}
response = requests.get(url, headers=headers)
result = response.json()
{
"method": "GET",
"url": "https://api.kwiga.com/coupons/:coupon",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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()
{
"method": "POST",
"url": "https://api.kwiga.com/coupons",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"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
}
}
Пример ответа:
{
"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
discount_with_percent or discount_with_currency2024-12-31 or 2024-12-31 23:59:59Структура ответа
Проверка купона
Пример запроса:
<?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()
{
"method": "POST",
"url": "https://api.kwiga.com/coupons/check",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/json",
"Content-Type": "application/json"
},
"body": {
"code": "VAJ6-EA",
"price": 65
}
}
Пример ответа:
{
"data": {
"can_use": true,
"discount": 6.5
}
}
POST https://api.kwiga.com/coupons/check
Проверяет купон на существование и возможность использования (не исчерпан лимит / не закончился срок действия).
Обратите внимание: при использовании на checkout странице купон может не применяться при следующих условиях: если на предложении выключено использование купонов/данного купона; на купоне стоят ограничения списками контактов; пользователь уже использовал купон и на купоне стоит ограничение по количеству использований.
Parameters
Структура ответа
Сертификаты
Получение сертификат по номеру
Пример запроса:
<?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()
{
"method": "GET",
"url": "https://api.kwiga.com/certificates/by-number/:number",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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",
"url": "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()
{
"method": "GET",
"url": "https://api.kwiga.com/timezones",
"headers": {
"Token": "<Token>",
"Cabinet-Hash": "<Cabinet-Hash>",
"Accept": "application/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
Теги, привязанные к контакту
Момент последней активности контакта в кабинете
Первый зафиксированный визит контакта
Агрегированная UTM-атрибуция по всем визитам контакта
Все UTM-отслеженные визиты контакта
Предложения, купленные контактом
Заказы, размещённые контактом
Кастомные поля кабинета, заполненные для этого контакта
Информация о выпущенных сертификатах по продуктам контакта
ContactIdentifier
ContactAdditionalField
Определение кастомного поля кабинета
ContactField
Токен формата ввода для поля
Выражение правила валидации
Идентификатор типа поля (text, number, date, enum и т.д.)
Порядок отображения внутри кабинета
Допустимые значения для enum-полей
Порядок отображения имени/фамилии, заданный в кабинете
ContactList
Идентификатор кабинета-владельца
Идентификатор пользователя-владельца
Email-рассылки, связанные со списком
Правила фильтрации, определяющие членство в сегменте
ContactListStatistic
FlowTag
Сколько контактов помечено этим тегом
Курсы
Course
CourseIdentify
Краткие идентификационные записи уроков курса
URL превью-картинки курса (или плейсхолдер по умолчанию, если изображение не задано)
Краткие идентификационные записи предложений, связанных с курсом
CourseLessonIdentify
CourseLessonSimple
Квизы, прикреплённые к уроку
Идентификационные данные родительского курса
CourseModuleSimple
CourseProgram
CourseProgress
CourseUser
include contains lesson_progress.Массив объектов `LessonProgress` — per-lesson снимки просмотра/завершения для этого пользователя. Возвращается при `include=lesson_progress`.
include contains module_progress.Массив объектов `ModuleProgress` — per-module снимки просмотра/завершения для этого пользователя (агрегируются сервером из уроков модуля). Возвращается при `include=module_progress`.
include contains quiz_progress.Массив объектов `QuizProgress` — по одной записи на пару `(course_lesson_id, quiz_id)` со сводкой по последней non-cancelled попытке ученика. Возвращается при `include=quiz_progress`.
InfoUnit
QuizIdentifier
QuizAttemptIdentifier
Метаданные квиза
Метаданные урока
Купоны
ExpertCoupon
Метаданные типа купона
Краткие идентификационные данные связанного контакта
Идентификационные данные предложений, на которые действует купон
Последний внутренний комментарий (для администраторов)
CouponType
CouponCheck
Сертификаты
Certificate
Когда пользователь завершил certificateble-сущность (курс и т.п.)
Баллы, набранные пользователем для получения сертификата
CertificateTemplate
StudentProductCertificateInfo
Название certificateble-сущности
Предложения
Offer
Цена с применённой активной скидкой
OfferIdentifier
OfferSimple
OfferDiscount
Краткие идентификационные данные родительского предложения
Заказы
Order
OrderFunnel
OrderGroup
OrderStage
Платежи
Payment
Transaction
Price
Currency
Продукты
Product
Публичная ссылка на productable-сущность
ProductIdentifier
ProductAggregatedSubscription
ProductSubscription
UserProduct
Агрегированная информация о доступе (общий is_active/start/end по всем подпискам)
Отдельные записи подписок (по одной на заказ/предложение)
EmailCampaign
Данные email-шаблона (системный или кастомный)
Полный снимок статистики рассылки
EmailCampaignIdentifier
Визиты
Visit
Информация о user agent / устройстве
VisitLocation
VisitUserAgent
UtmList
Комментарии
CommentIdentifier
Краткое представление целевой сущности
Попытки квизов
QuizAttempt
Статус попытки в виде enum-объекта — id (числовое значение), slug (стабильное имя кейса) и title (подпись, уже переведённая под локаль кабинета).
1— Пройдено2— Не пройдено3— Требуется доработка4— Последняя версия изменила статус5— В процессе6— Ожидает проверки7— Не приступал
InfoSectionReport
Награды (геймификация)
FlowRewardLog
points — accrued или deducted. Совпадает со значениями фильтра accrual_type в списке.
Почему появилась эта запись. Возможные id:
1— Практика пройдена2— Отмена результатов практики3— Сброс баллов за попытку4— Новые баллы за попытку5— Оплата баллами6— Вручную7— Автоматизация8— Изменены баллы за попытку9— Оплата баллами за подарок
event). Для ручных — NULL.
quiz_attempt, order, gift). Для ручных — NULL.
eventable_type. Для ручных — NULL.
manual_comment ученику в его собственном журнале баллов. Для не-ручных записей — NULL. Кураторы (включая этот API) видят комментарий всегда, независимо от флага.