Cuotas, apuestas y cupones — documentación técnica de API
Este archivo contiene un script mínimo e independiente para conectarse al sistema de cálculo de cupones SportAPI. Los detalles y los casos raros se encuentran en documentación completa.
POST /api/partner/login
POST /api/partner/coupons/place
GET /api/partner/coupons/calculated?time=10 1. Lo que necesitas obtener del gerente.
- API de URL base;
- inicio de sesión y contraseña de la cuenta del cliente;
- cuando utilice la devolución de llamada, habilite la función y la frase secreta
callback_secret.
Los ejemplos utilizan una dirección condicional:
BASE_URL="https://coupon-api.example.com"
En producción, utilice HTTPS. Todas las fechas se transmiten como marca de tiempo Unix en milisegundos y los valores monetarios se transmiten como números decimales sin precisión fija.
2. Formato de respuesta API
Éxito:
{
"code": 1,
"body": {},
"error_code": null,
"error_message": null,
"date": 1784970000000,
"time_ms": 5,
"path": "/api/partner/example"
}
El error comercial generalmente también viene con HTTP 200:
{
"code": 0,
"body": null,
"error_code": 1002,
"error_message": "Not all params",
"date": 1784970000000,
"time_ms": 5,
"path": "/api/partner/example"
}
Verifique siempre el código HTTP, luego code, luego error_code. No utilice el texto error_message como clave de software.
3. Autorización
POST /api/partner/login
Content-Type: application/json
{
"username": "partner-demo",
"password": "strong-password"
}
El campo login se admite como alias compatible username.
Respuesta exitosa:
{
"code": 1,
"body": {
"token": "<jwt-token>",
"user_id": 17,
"username": "partner-demo"
},
"error_code": null,
"error_message": null
}
En todas las solicitudes protegidas, pase:
Authorization: Bearer <jwt-token>
Errores básicos de inicio de sesión:
| Código | Razón |
|---|---|
1002 | Nombre de usuario o contraseña no enviados. |
1003 | Inicio de sesión desconocido o contraseña incorrecta. |
1004 | La cuenta del cliente ha sido deshabilitada. |
1006 | La fecha de acceso ha caducado. |
1007 | El saldo del cliente es cero o negativo. |
Estos errores se devuelven desde HTTP 200, code = 0. HTTP 401 de un método protegido significa que el JWT falta, no es válido, ha caducado o está revocado; Inicia sesión nuevamente. HTTP 403 significa rol inadecuado o acceso denegado.
4. Indicador de tarifa
Cada resultado seleccionado se transmite como una línea ya preparada de la línea deportiva:
line_type#game_id#group_id#type_id#rate#coefficient[#player_id]
Ejemplos:
line#737779544#1#1#0#1.85
live#738917381|119|5869|0.5#3.6#149439538
line_type:lineolive;rate: parámetro total/handicap o0;player_id: ID de jugador opcional;- Se admiten los delimitadores
#y|.
No recopile ni corrija el puntero manualmente; pase el valor obtenido de la línea sin cambios.
5. Crear un cupón
POST /api/partner/coupons/place
Authorization: Bearer <jwt-token>
Content-Type: application/json
{
"list_bets": [
"line#737779544#1#1#0#1.85"
],
"amount": 10,
"currency": "USD",
"callback_url": "https://partner.example.com/api/coupon-result",
"lang": "en",
"mode": "reject",
"mode_type": null,
"multi": false
}
| campo | Obligatorio | Propósito |
|---|---|---|
list_bets | si | Uno o más punteros. |
amount | si | Se crea el importe positivo de un cupón. |
currency | No | Cualquier designación de cadena, incluida la moneda virtual. |
callback_url | No | devolución de llamada de URL; sin una devolución de llamada no puede enviarlo, puede pasar null, una cadena vacía o un dominio de sitio. |
lang | No | Un código de dos letras para uno de los aproximadamente 50 idiomas admitidos. El lenguaje de los nombres se fija en el momento de la creación. |
mode | No | reject o accept; predeterminado reject. |
mode_type | Para accept | Dirección permitida del cambio de coeficiente. |
multi | No | Un cupón general o individual individual; predeterminado false. |
probabilidades
| Configuración | Comportamiento |
|---|---|
mode = reject | Rechazar la creación cuando cambie el coeficiente. |
mode = accept, mode_type = 1 | Acepta sólo promociones. |
mode = accept, mode_type = 2 | Acepte sólo la degradación. |
mode = accept, mode_type = 3 | Acepta cualquier cambio. |
Ordinario, expreso y multi
| Solicitar | Resultado | Cancelación del saldo del cliente |
|---|---|---|
| Un resultado | uno ordinario | amount |
Múltiples resultados, multi = false | un expreso | amount |
Múltiples resultados, multi = true | Sencillo separado para cada resultado | amount × número de cupones creados |
Un tren expreso no puede contener más de 15 eventos. No puedes combinar múltiples apuestas en el mismo partido, incluido el partido principal, mitades, períodos, córners, faltas y otros subeventos relacionados. Esta combinación devuelve 506.
6. Confirmación de creación de cupón y oferta.
Respuesta completa exitosa con cupón y datos de apuesta aceptada dentro de events_data:
{
"code": 1,
"body": {
"coupons": [
{
"coupon_code": "000000000272",
"amount": 10,
"win": 18.5,
"potential_win": 18.5,
"real_win": null,
"coef": 1.85,
"original_coef": 1.85,
"calculate_coef": null,
"has_return": false,
"date": 1784970000000,
"status": 0,
"asian": false,
"calculate_date": null,
"coupon_type": 1,
"events_count": 1,
"events_data": [
{
"id": 912,
"game_id": 737779544,
"main_game_id": 737779544,
"is_sub_game": false,
"parent_game_id": null,
"sub_game_key": null,
"raw_pointer": "line#737779544#1#1#0#1.85",
"line_type": "line",
"is_live": false,
"bet_group_id": 1,
"bet_group_name": "Match result",
"bet_id": 1,
"bet_name": "First team to win",
"sport_id": 1,
"sport_name": "Football",
"tournament_id": 10001,
"tournament": "National League",
"event_date": 1784971800000,
"status": 0,
"opp1": "Team A",
"opp2": "Team B",
"coef": 1.85,
"calc_coef": null,
"bet_score": "line#737779544#1#1#0#1.85",
"calculate_date": null,
"calculate_score": null,
"settlement_reason_code": null,
"settlement_reason": null,
"placement_score_full": null,
"placement_score_periods": null,
"calculation_score_full": null,
"calculation_score_periods": null,
"timer": null,
"dop_name": null,
"rate": "0",
"sgame_id": null,
"game_num": null,
"stat_id": null,
"team1_id": 101,
"team2_id": 102,
"opp_icon1": 101,
"opp_icon2": 102
}
]
}
]
},
"error_code": null,
"error_message": null,
"date": 1784970000015,
"time_ms": 45,
"path": "/api/partner/coupons/place"
}
Campos de cupón
Cada artículo body.coupons[] es un cupón independiente creado.
| campo | Tipo | Significado |
|---|---|---|
coupon_code | string | Código de cupón público de 12 dígitos. Guárdelo como una cadena para evitar perder los ceros a la izquierda. |
amount | number | El monto del cupón transferido al momento de la creación. |
win | number | Monto ganador mostrado actualmente. |
potential_win | number | Posibles ganancias antes de la liquidación final. |
real_win | number/null | Monto de pago real después del cálculo; antes del cálculo - null. |
coef | number | Relación de cupón actual o final. |
original_coef | number | El coeficiente total del cupón en el momento de su creación. |
calculate_coef | number/null | Coeficiente calculado final; antes del cálculo - null. |
has_return | boolean | true, si el cupón contiene una apuesta con estado de reembolso. |
date | integer | Fecha de creación del cupón, marca de tiempo Unix en milisegundos. |
status | integer | Estado actual del cupón. Los valores se describen en la sección “Estado del cupón y de la oferta”. |
asian | boolean | Signo de la presencia de un acuerdo asiático, incluida la mitad de ganancias o pérdidas. |
calculate_date | integer/null | Fecha de cálculo del cupón en milisegundos; antes del cálculo - null. |
coupon_type | integer | Tipo de cupón: 1 - ordinario, 2 - exprés. |
events_count | integer | Número de apuestas dentro del cupón. |
events_data | array | Toda la gama de apuestas incluidas en el cupón. |
Campos de oferta
Cada elemento de events_data[] describe una apuesta aceptada específica dentro del cupón.
| campo | Tipo | Significado |
|---|---|---|
id | integer/null | ID interno de la apuesta aceptada. Se utiliza junto con coupon_code para buscar una tarifa dentro de un cupón. |
game_id | integer | ID del evento o subevento en el que se realiza la apuesta. |
main_game_id | integer/null | ID del partido principal al que pertenece el evento o subevento. |
is_sub_game | boolean | true, si la apuesta se relaciona con una mitad, período, set, córners u otro subevento. |
parent_game_id | integer/null | El ID del evento principal inmediato, si existe. |
sub_game_key | string/null | Clave técnica de un subevento o período. |
raw_pointer | string | El indicador de tasa original aceptado por la API. |
line_type | string | Tipo de línea: line - pre-partido, live - evento en tiempo real. |
is_live | boolean | true, si la apuesta se creó en una línea viva. |
bet_group_id | integer | ID del grupo de apuesta o mercado. |
bet_group_name | string/null | Nombre localizado del grupo de apuestas. |
bet_id | integer | ID de la selección seleccionada dentro del grupo de apuestas. |
bet_name | string/null | Nombre completo localizado de la selección seleccionada. |
sport_id | integer/null | Identificación deportiva. |
sport_name | string/null | Nombre localizado del deporte. |
tournament_id | integer/null | Identificación del torneo. |
tournament | string/null | Nombre localizado del torneo. |
event_date | integer/null | Fecha de inicio del evento, marca de tiempo de Unix en milisegundos. |
status | integer | Estado actual del cálculo de la tarifa. No confundir con el estado del cupón. |
opp1 | string/null | Nombre del primer equipo o participante. |
opp2 | string/null | Nombre del segundo equipo o participante. |
coef | number | Las probabilidades de apuesta a las que se aceptó la apuesta. |
calc_coef | number/null | Multiplicador de apuesta calculado; antes del cálculo - null. |
bet_score | string | Campo compatible con API heredada que contiene el indicador de apuesta en lugar del resultado del partido. |
calculate_date | integer/null | Fecha de cálculo de la tarifa en milisegundos; antes del cálculo - null. |
calculate_score | string/null | La cuenta utilizada para calcular la apuesta. |
settlement_reason_code | string/null | Código de máquina estable del motivo del pago o devolución; antes del cálculo - null. |
settlement_reason | string/null | Texto explicativo del motivo del pago o devolución; antes del cálculo - null. |
placement_score_full | string/null | Puntuación total del evento en el momento en que se creó la apuesta, si está disponible. |
placement_score_periods | string/null | Puntuación por período en el momento en que se creó la apuesta, si está disponible. |
calculation_score_full | string/null | La puntuación total del evento en el momento en que se liquida la apuesta. |
calculation_score_periods | string/null | Cuenta por período al momento del cálculo de la tarifa. |
timer | integer/null | Temporizador de eventos en el momento de guardar los datos, si está disponible. |
dop_name | string/null | Nombre del subevento: mitad, período, set, entrada, etc. |
rate | string | Parámetro de resultado, por ejemplo, el valor del total o handicap; para un resultado sin parámetro - "0". |
sgame_id | string/null | Clave externa del subevento. |
game_num | integer/null | Número de juego, si lo proporciona la fuente. |
stat_id | string/null | ID de evento estadístico externo. |
team1_id | integer/null | DNI del primer equipo o participante. |
team2_id | integer/null | DNI del segundo equipo o participante. |
opp_icon1 | integer/null | ID compatible del primer icono de comando; coincide con team1_id. |
opp_icon2 | integer/null | ID de icono del segundo equipo compatible; coincide con team2_id. |
El valor null es normal para datos que aún no se han calculado o no están disponibles. No lo reemplace automáticamente con 0 o la cadena vacía.
Considere el cupón aceptado sólo si code = 1 y la presencia de objetos en body.coupons. Ante esto, la canasta es una elección preliminar: la selección podría desaparecer, ser bloqueada o cambiar las cuotas.
Después del éxito:
- guarde todos los objetos
body.coupons, no solo el primero; - almacene
coupon_codecomo una cadena con ceros a la izquierda; - guarde los datos requeridos de
events_data; - hacer coincidir el cupón con el usuario final;
- registrar la transacción financiera del usuario en el sistema del socio.
Identificadores:
| campo | Propósito |
|---|---|
coupon_code | Código de cupón público. |
events_data[].id | ID de la apuesta aceptada específica dentro del cupón. |
devolución de llamada events_data[].uuid | El mismo ID de oferta, pasado como una cadena. |
batchId | ID de la versión del paquete de devolución de llamada, no el cupón o la tarifa. |
currency no se devuelve en el modelo completo ni en la devolución de llamada. Si se necesita la moneda, guarde el valor de la solicitud de creación.
7. Errores de creación
| Código | Razón | acción |
|---|---|---|
10 | Sin cuerpo de solicitud. | Corrija la solicitud. |
11 | Puntero no válido. | Obtenga el puntero actual de la línea. |
12 | amount no válido. | Pase un número positivo. |
501 | El coeficiente ha cambiado. | Mostrar nuevo valor o cambiar mode. |
502 | No hay resultado. | Eliminar/actualizar oferta en el carrito. |
503 | El resultado está bloqueado. | Informar indisponibilidad temporal. |
504 | Error de verificación de resultados. | No dar por aceptado el cupón; repetir más tarde. |
506 | En apuestas express un partido. | Deje un resultado o utilice sencillos separados. |
507 | Saldo de cliente insuficiente. | Recarga tu saldo o reduce el importe total. |
1002 | Conjunto de parámetros no válido. | Parámetros correctos. |
10000 | Error interno. | Registre el error y verifique el resultado antes de volver a intentarlo. |
Para 501–504, la nueva API devuelve las tasas problemáticas en body.changes[]. Campo change_type: 1: el coeficiente ha aumentado, 2: disminuido, null: la dirección no es aplicable.
No vuelva a intentar ciegamente POST /coupons/place después del tiempo de espera: es posible que la primera solicitud haya sido aceptada y volver a intentarlo creará un duplicado.
8. Recibir cupones
| Operación | Punto final | Resultado |
|---|---|---|
| Un cupón | GET /api/partner/coupons/get?coupon_code={code} | Cupón en body. |
| Activo | GET /api/partner/coupons/active | Matriz en body[]. |
| Cálculos recientes | GET /api/partner/coupons/calculated?time=10 | Matriz en body[]; máximo 120 minutos. |
| Por código/período | POST /api/partner/coupons/results | Matriz en body.coupons. |
| Saldo del cliente | GET /api/partner/balance | body.balance. |
Puede transferir hasta 100 valores usando códigos:
{
"coupon_ids": ["000000000272", "000000000273"]
}
O pasar el período de creación no más de 24 horas:
{
"start_date": 1784880000000,
"end_date": 1784966400000
}
No combine coupon_ids y fechas en la misma consulta. results filtra por hora de creación y calculated filtra por hora de liquidación final.
9. Estados de cupones y apuestas
Estados de los cupones:
| Código | Significado | finales |
|---|---|---|
0 | Activo o parcialmente liquidado. | No |
2 | Ganado. | si |
4 | Perdido. | si |
8 | Totalmente reembolsado. | si |
15 | Devuelto para nuevo cálculo; esperar un nuevo resultado. | No |
Estados de las ofertas:
| Código | Significado | calc_coef |
|---|---|---|
0 | No calculado. | null |
1 | Ganando. | Coeficiente original |
2 | Perdiendo. | 0 |
3 | Regreso. | 1 |
4 | A la espera de nuevo cálculo. | null |
21 | La mitad de las ganancias. | (coef + 1) / 2 |
22 | Media pérdida. | 0.5 |
23 | Empujar. | 1 |
Para la acumulación financiera para el usuario final, utilice el real_win ya preparado. No utilice potential_win y no vuelva a calcular el pago usted mismo. Antes del cálculo, real_win, calculate_coef, calc_coef y calculate_date son iguales a null, no a 0.
En el primer estado del cupón 15, si el resultado anterior ya ha sido procesado financieramente, el socio debita nuevamente amount del usuario final, espera un nuevo estado final y cobra un nuevo real_win. Proteger las operaciones del reprocesamiento.
10. Razón del cálculo
Cada apuesta en el modelo completo y callback tiene:
| campo | Propósito |
|---|---|
settlement_reason_code | Código de motivo de pago/reembolso estable. |
settlement_reason | Texto fuente explicativo. |
Antes del cálculo, ambos campos son iguales a null. Para una notificación localizada, use código como:
MATCH_POSTPONED- el partido ha sido pospuesto;MATCH_CANCELLED- partido cancelado;MARKET_PUSH- devolución según las reglas del mercado.
Si desconoce el código, guárdelo y utilice el settlement_reason que no esté vacío como texto alternativo. No calcule el pago por motivo: utilice estados y real_win.
Estos campos explican el cálculo o la devolución que ya se ha realizado y no son una fuente separada en tiempo real del estado del partido.
11. devolución de llamada
La devolución de llamada es opcional. Un socio sólo puede trabajar mediante encuestas. Para la devolución de llamada, el administrador debe habilitar la función y crear callback_secret; La URL se envía en cada cupón creado.
El socio determina la URL de devolución de llamada de forma independiente. En producción se deberá utilizar https://; en un entorno de prueba, se permite http://.
El sistema envía:
POST {callback_url}
Content-Type: application/json
X-Coupon-Signature: sha256=<hex_hmac_sha256>
Carga útil corta:
{
"event": "coupons.settled",
"batchId": "d407e986f3a64d9d36a77bf532322ef8",
"couponCount": 1,
"coupons": [
{
"coupon_code": "000000000272",
"realWin": 18.5,
"calculate_coefficient": 1.85,
"status": 2,
"calculate_date": 1784973600000,
"events_data": [
{
"uuid": "912",
"status": 1,
"calculate_coefficient": 1.85,
"calculate_date": 1784973600000,
"calculate_score": "2:1",
"settlement_reason_code": "REMOTE_WIN",
"settlement_reason": "Win",
"timer": 0
}
]
}
]
}
Reglas obligatorias:
- calcule
sha256=<hex(HMAC-SHA256(raw_body, callback_secret))>a partir de los bytes de origen exactos del cuerpo antes de analizar JSON y comparar firmas de forma segura; - procese todos los artículos
coupons, el paquete puede contener hasta 100 cupones; - almacene
batchIdcon un índice único; - repetido
batchIdno debe repetir la cancelación o acumulación; - un
coupon_codepuede venir con diferentesbatchIddurante el cálculo progresivo y el recálculo; - devuelva HTTP
200solo después de que todo el paquete se haya almacenado de forma segura.
La respuesta mínima exitosa es un HTTP 200 vacío. Avanzado:
{
"success": true,
"processed": 1
}
processed debe ser igual a couponCount. Las respuestas 201, 202 y 204 no se consideran exitosas.
Las repeticiones se realizan solo en caso de tiempo de espera, error de transporte o HTTP 500, 502, 503, 504: inmediatamente, luego después de 1, 5, 15 y 60 minutos, no más de cinco envíos. No hay reintento automático en HTTP 200 con success: false o processed parcial.
12. Encuesta de reserva
Incluso con devolución de llamada, verifique periódicamente los resultados:
GET /api/partner/coupons/calculated?time=10
Después de una pausa de más de 120 minutos, use POST /api/partner/coupons/results sobre coupon_ids guardado o períodos de creación de hasta 24 horas. Recibir nuevamente la misma fortuna no debería repetir transacciones financieras.
13. Seguridad y almacenamiento
- almacene el inicio de sesión, la contraseña, JWT y
callback_secretsolo en el servidor; - no pase JWT en la URL y no escriba el token completo en los registros;
- use tipo decimal para dinero;
- almacene
coupon_codecomo una cadena; - guarde
amount, los datos de oferta requeridos ycurrency, si se utilizan; - distinguir entre estados de cupón y oferta;
- aceptar campos desconocidos y códigos de motivo sin errores;
- Haga que todas las transacciones financieras del usuario final sean idempotentes.
14. API antigua y retiro
Se siguen admitiendo rutas antiguas, pero las nuevas integraciones deben utilizar /api/partner/**. Las respuestas antiguas y los errores tienen formatos diferentes. Para actualizar un cliente existente, utilice un único archivo “Migración desde la API anterior”.
El retiro está en desarrollo, no está completamente probado y no se recomienda su producción.
15. Lista de verificación final
- Recibido
BASE_URL, nombre de usuario y contraseña. - JWT se transmite como un token al portador.
- Los punteros se toman de la línea sin modificaciones.
- El carrito se guarda como cupón aceptado solo después de
code = 1. - Procesado
multi, restricciones expresas y errores501–507. - Se ha tenido en cuenta la cancelación automática del saldo del cliente.
- Se guardan todos los
coupon_codey los ID de oferta. - El pago final se obtiene de
real_win. - La devolución de llamada se compara con los bytes de origen y se deduplica mediante
batchId. - Se ha configurado el sondeo de respaldo.
- El saldo del usuario es independiente del saldo del cliente SportAPI.
La documentación detallada comienza con descripción general de API. El mapa completo de terminales se encuentra en manual.