SportAPI Документация
RU
C Документация продуктаCoupon API
v1
Услуга и цены ↗ Получить доступ ↗
Coupon API / cURL

Coupon API — примеры запросов cURL

На этой странице показан проверенный сценарий: авторизация, получение актуального исхода из Sport Line API, формирование полного указателя ставки, создание ординара и получение созданного купона.

Перед началом

Понадобятся curl и jq. Подготовьте переменные только в текущей серверной сессии:

COUPON_API_BASE_URL='https://YOUR_COUPON_API_DOMAIN'
COUPON_LOGIN='YOUR_LOGIN'
COUPON_PASSWORD='YOUR_PASSWORD'

SPORT_LINE_BASE_URL='https://YOUR_SPORT_LINE_DOMAIN'
SPORT_LINE_PACKAGE='YOUR_SPORT_LINE_API_KEY'

Не добавляйте реальные значения в исходный код или документацию.

Шаг 1. Получите JWT

LOGIN_RESPONSE=$(curl --silent --show-error --request POST \
  --url "$COUPON_API_BASE_URL/api/partner/login" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data "$(jq -nc \
    --arg username "$COUPON_LOGIN" \
    --arg password "$COUPON_PASSWORD" \
    '{username:$username,password:$password}')")

TOKEN=$(printf '%s' "$LOGIN_RESPONSE" | jq -er \
  'select(.code == 1) | .body.token')

Не выводите $TOKEN в журнал. Если jq завершился с ошибкой, изучите безопасную часть ответа:

printf '%s' "$LOGIN_RESPONSE" | jq \
  '{code, error_code, error_message, path}'

Подробнее: «Авторизация».

Шаг 2. Найдите матч в спортивной линии

Сначала получите актуальное Live-меню:

curl --request GET \
  --url "$SPORT_LINE_BASE_URL/v1/menu/live/en" \
  --header "Package: $SPORT_LINE_PACKAGE" \
  --header 'Accept: application/json'

Выберите sport_id и tournament_id, затем запросите матчи:

SPORT_ID='SPORT_ID_FROM_MENU'
TOURNAMENT_ID='TOURNAMENT_ID_FROM_MENU'

curl --request GET \
  --url "$SPORT_LINE_BASE_URL/v1/events/$SPORT_ID/$TOURNAMENT_ID/sub/50/live/en" \
  --header "Package: $SPORT_LINE_PACKAGE" \
  --header 'Accept: application/json'

Возьмите актуальный game_id из body[].events_list[]. Подробности приведены в описаниях методов menu и events.

Шаг 3. Получите исход и коэффициент

GAME_ID='GAME_ID_FROM_EVENTS'

EVENT_RESPONSE=$(curl --silent --show-error --request GET \
  --url "$SPORT_LINE_BASE_URL/v1/event/$GAME_ID/group/live/en" \
  --header "Package: $SPORT_LINE_PACKAGE" \
  --header 'Accept: application/json')

Выберите первый незаблокированный исход без персонального player_id:

SELECTION=$(printf '%s' "$EVENT_RESPONSE" | jq -ec '
  [.. | objects
    | select(
        has("oc_pointer") and
        (.oc_block == false or .oc_block == 0 or .oc_block == null) and
        (.oc_rate | type == "number") and
        (.op_id == null)
      )
  ] | first
')

OC_POINTER=$(printf '%s' "$SELECTION" | jq -r '.oc_pointer')
COEFFICIENT=$(printf '%s' "$SELECTION" | jq -r '.oc_rate')

Проверить выбранный исход без вывода доступов:

printf '%s' "$SELECTION" | jq \
  '{oc_name, oc_group_name, oc_pointer, oc_rate}'

Подробнее: event и «Коэффициенты и группы ставок».

Шаг 4. Сформируйте полный указатель ставки

oc_pointer спортивной линии содержит технические части game_id|group_id|type_id|rate, но не является полным указателем Coupon API. Для Live добавьте тип линии и актуальный oc_rate:

NORMALIZED_POINTER=${OC_POINTER//|/#}
BET_POINTER="live#$NORMALIZED_POINTER#$COEFFICIENT"

Результат имеет формат:

live#game_id#group_id#type_id#rate#coefficient

Для Prematch используйте запросы линии с типом line и префикс line. Не используйте устаревший коэффициент: непосредственно перед созданием купона повторно получите исход.

Подробнее: «Указатель ставки».

Шаг 5. Создайте тестовый ординар

PLACE_RESPONSE=$(curl --silent --show-error --request POST \
  --url "$COUPON_API_BASE_URL/api/partner/coupons/place" \
  --header 'Accept: application/json' \
  --header "Authorization: Bearer $TOKEN" \
  --header 'Content-Type: application/json' \
  --data "$(jq -nc \
    --arg pointer "$BET_POINTER" \
    '{
      list_bets: [$pointer],
      amount: 10,
      currency: "USD",
      callback_url: null,
      lang: "en",
      mode: "reject",
      mode_type: null,
      multi: false
    }')")

Покажите только основные поля результата:

printf '%s' "$PLACE_RESPONSE" | jq '{
  code,
  error_code,
  error_message,
  coupons: [.body.coupons[]? | {
    coupon_code,
    amount,
    coef,
    status
  }]
}'

Успех подтверждается одновременно HTTP-ответом без ошибки и code = 1. Сохраните body.coupons[].coupon_code как строку: код может содержать ведущие нули.

Подробнее: «Создание купона».

Шаг 6. Создайте экспресс

Для экспресса подготовьте минимум два актуальных указателя из разных матчей:

BET_POINTER_1='live#GAME_ID_1#GROUP_ID#TYPE_ID#RATE#COEFFICIENT'
BET_POINTER_2='live#GAME_ID_2#GROUP_ID#TYPE_ID#RATE#COEFFICIENT'

Не объединяйте в экспресс исходы основного матча и его саб-событий. Все элементы list_bets должны относиться к разным матчам.

Отправьте указатели с multi: false:

EXPRESS_RESPONSE=$(curl --silent --show-error --request POST \
  --url "$COUPON_API_BASE_URL/api/partner/coupons/place" \
  --header 'Accept: application/json' \
  --header "Authorization: Bearer $TOKEN" \
  --header 'Content-Type: application/json' \
  --data "$(jq -nc \
    --arg pointer1 "$BET_POINTER_1" \
    --arg pointer2 "$BET_POINTER_2" \
    '{
      list_bets: [$pointer1, $pointer2],
      amount: 10,
      currency: "USD",
      callback_url: null,
      lang: "en",
      mode: "reject",
      mode_type: null,
      multi: false
    }')")

Проверьте структуру созданного экспресса:

printf '%s' "$EXPRESS_RESPONSE" | jq '{
  code,
  error_code,
  error_message,
  coupons: [.body.coupons[]? | {
    coupon_code,
    amount,
    coef,
    coupon_type,
    events_count,
    status
  }]
}'

Успешный ответ содержит один элемент body.coupons, coupon_type = 2 и events_count = 2. Поле amount относится ко всему экспрессу, а coef содержит итоговый коэффициент.

Шаг 7. Создайте несколько ординаров через multi

Чтобы те же два указателя стали отдельными ординарами, передайте multi: true:

MULTI_RESPONSE=$(curl --silent --show-error --request POST \
  --url "$COUPON_API_BASE_URL/api/partner/coupons/place" \
  --header 'Accept: application/json' \
  --header "Authorization: Bearer $TOKEN" \
  --header 'Content-Type: application/json' \
  --data "$(jq -nc \
    --arg pointer1 "$BET_POINTER_1" \
    --arg pointer2 "$BET_POINTER_2" \
    '{
      list_bets: [$pointer1, $pointer2],
      amount: 10,
      currency: "USD",
      callback_url: null,
      lang: "en",
      mode: "reject",
      mode_type: null,
      multi: true
    }')")

Проверьте отдельные купоны и общую сумму:

printf '%s' "$MULTI_RESPONSE" | jq '{
  code,
  coupon_count: (.body.coupons | length),
  total_amount: ([.body.coupons[].amount] | add),
  coupons: [.body.coupons[] | {
    coupon_code,
    amount,
    coef,
    coupon_type,
    events_count,
    status
  }]
}'

При двух указателях API возвращает два ординара с разными coupon_code. Значение amount применяется полностью к каждому ординару: при amount = 10 общая сумма равна 20, а не 10.

Подробнее: «Ординары, экспрессы и multi».

Шаг 8. Получите созданный купон

COUPON_CODE=$(printf '%s' "$PLACE_RESPONSE" | jq -er \
  'select(.code == 1) | .body.coupons[0].coupon_code')

COUPON_RESPONSE=$(curl --silent --show-error --request GET \
  --url "$COUPON_API_BASE_URL/api/partner/coupons/get?coupon_code=$COUPON_CODE" \
  --header 'Accept: application/json' \
  --header "Authorization: Bearer $TOKEN")

В этом методе один купон находится непосредственно в body, а не в body.coupons. Выведите его состояние и статусы ставок:

printf '%s' "$COUPON_RESPONSE" | jq '
  def coupon_status:
    {"0":"NEW", "2":"WIN", "4":"LOSE", "8":"RETURN", "15":"UPDATE"}
    [tostring] // "UNKNOWN";
  def bet_status:
    {"0":"NET", "1":"WIN", "2":"LOSE", "3":"RETURN", "4":"RECALCULATE",
     "21":"HALF_WIN", "22":"HALF_LOSE", "23":"PUSH"}
    [tostring] // "UNKNOWN";
  .body | {
    coupon_code,
    status,
    status_name: (.status | coupon_status),
    amount,
    coef,
    calculate_coef,
    real_win,
    calculate_date,
    events: [.events_data[] | {
      game_id,
      bet_name,
      status,
      status_name: (.status | bet_status),
      coef,
      calc_coef,
      calculate_score
    }]
  }
' 

Статусы купона и отдельной ставки имеют разные таблицы значений. Например, 2 означает выигрыш купона, но проигрыш отдельной ставки. Не интерпретируйте эти поля одной общей таблицей.

Подробнее: «Получение купона».

Шаг 9. Получите активные купоны

ACTIVE_RESPONSE=$(curl --silent --show-error --request GET \
  --url "$COUPON_API_BASE_URL/api/partner/coupons/active" \
  --header 'Accept: application/json' \
  --header "Authorization: Bearer $TOKEN")

printf '%s' "$ACTIVE_RESPONSE" | jq '{
  code,
  count: (.body | length),
  coupons: [.body[] | {
    coupon_code,
    status,
    amount,
    coef,
    coupon_type,
    events_count
  }]
}'

Массив купонов находится непосредственно в body. Пустой массив является успешным ответом и означает, что активных купонов сейчас нет.

Шаг 10. Получите недавно рассчитанные купоны

CALCULATED_RESPONSE=$(curl --silent --show-error --request GET \
  --url "$COUPON_API_BASE_URL/api/partner/coupons/calculated?time=120" \
  --header 'Accept: application/json' \
  --header "Authorization: Bearer $TOKEN")

printf '%s' "$CALCULATED_RESPONSE" | jq '{
  code,
  count: (.body | length),
  coupons: [.body[] | {
    coupon_code,
    status,
    amount,
    calculate_coef,
    real_win,
    calculate_date
  }]
}'

Параметр time задаёт окно по времени окончательного расчёта в минутах. Допустимое значение ограничивается 120 минутами. Активные купоны этот метод не возвращает.

Шаг 11. Получите несколько известных купонов по кодам

COUPON_CODE_1='FIRST_COUPON_CODE'
COUPON_CODE_2='SECOND_COUPON_CODE'

RESULTS_RESPONSE=$(curl --silent --show-error --request POST \
  --url "$COUPON_API_BASE_URL/api/partner/coupons/results" \
  --header 'Accept: application/json' \
  --header "Authorization: Bearer $TOKEN" \
  --header 'Content-Type: application/json' \
  --data "$(jq -nc \
    --arg code1 "$COUPON_CODE_1" \
    --arg code2 "$COUPON_CODE_2" \
    '{coupon_ids: [$code1, $code2]}')")

printf '%s' "$RESULTS_RESPONSE" | jq '{
  code,
  count: (.body.coupons | length),
  coupons: [.body.coupons[] | {
    coupon_code,
    status,
    amount,
    real_win,
    coupon_type,
    events_count
  }]
}'

В групповом методе массив находится в body.coupons. Ответ может содержать меньше купонов и в другом порядке, поэтому сопоставляйте записи только по coupon_code, а не по индексу массива.

Подробнее: «Активные и рассчитанные купоны», «Получение купонов списком и по периоду» и «Статусы и расчёт выплаты».

Частые ошибки

РезультатПричинаДействие
HTTP 401JWT отсутствует или больше не действуетВыполнить вход повторно один раз
error_code = 11Передан неполный или неверный указательПроверить наличие типа линии и коэффициента
error_code = 501Коэффициент изменилсяПовторно получить исход и применить правила mode
error_code = 502Исход исчез из линииПредложить пользователю выбрать другой исход
error_code = 503Исход заблокированНе отправлять ставку повторно без обновления линии

Не повторяйте запрос создания вслепую после сетевого timeout: первый запрос мог быть принят и повтор создаст второй купон.