SportApi
Documentation API · version 1.2.0

Cotes, paris et coupons — documentation technique de l’API

Ce fichier contient un script autonome minimal pour la connexion au système de calcul de coupons SportAPI. Les détails et les cas rares se trouvent dans la documentation complète.

Flux principal http
POST /api/partner/login
POST /api/partner/coupons/place
GET  /api/partner/coupons/calculated?time=10

1. Ce que vous devez obtenir du gestionnaire

  • API d’URL de base ;
  • identifiant et mot de passe du compte client ;
  • lors de l’utilisation du rappel - activez la fonction et la phrase secrète callback_secret.

Les exemples utilisent une adresse conditionnelle :

BASE_URL="https://coupon-api.example.com"

En production, utilisez HTTPS. Toutes les dates sont transmises sous forme d’horodatage Unix en millisecondes et les valeurs monétaires sont transmises sous forme de nombres décimaux sans précision fixe.

2. Format de réponse API

Succès :

{
  "code": 1,
  "body": {},
  "error_code": null,
  "error_message": null,
  "date": 1784970000000,
  "time_ms": 5,
  "path": "/api/partner/example"
}

L’erreur commerciale est généralement également accompagnée du HTTP 200 :

{
  "code": 0,
  "body": null,
  "error_code": 1002,
  "error_message": "Not all params",
  "date": 1784970000000,
  "time_ms": 5,
  "path": "/api/partner/example"
}

Vérifiez toujours le code HTTP, puis code, puis error_code. N’utilisez pas le texte error_message comme clé logicielle.

3. Autorisation

POST /api/partner/login
Content-Type: application/json
{
  "username": "partner-demo",
  "password": "strong-password"
}

Le champ login est pris en charge en tant qu’alias compatible username.

Réponse réussie :

{
  "code": 1,
  "body": {
    "token": "<jwt-token>",
    "user_id": 17,
    "username": "partner-demo"
  },
  "error_code": null,
  "error_message": null
}

Dans toutes les requêtes protégées, transmettez :

Authorization: Bearer <jwt-token>

Erreurs de connexion de base :

CoderRaison
1002Login ou mot de passe non envoyé.
1003Identifiant inconnu ou mot de passe incorrect.
1004Le compte client a été désactivé.
1006La date d’accès a expiré.
1007Le solde du client est nul ou négatif.

Ces erreurs sont renvoyées par HTTP 200, code = 0. HTTP 401 d’une méthode protégée signifie que le JWT est manquant, invalide, expiré ou révoqué ; Connectez-vous à nouveau. HTTP 403 signifie un rôle inapproprié ou un accès refusé.

4. Indicateur de taux

Chaque résultat sélectionné est transmis sous forme de ligne prête à l’emploi à partir de la ligne sportive :

line_type#game_id#group_id#type_id#rate#coefficient[#player_id]

Exemples :

line#737779544#1#1#0#1.85
live#738917381|119|5869|0.5#3.6#149439538
  • line_type : line ou live ;
  • rate : paramètre total/handicap ou 0 ;
  • player_id : ID de joueur en option ;
  • les délimiteurs # et | sont pris en charge.

Ne collectez pas et ne corrigez pas le pointeur manuellement - transmettez la valeur obtenue à partir de la ligne inchangée.

5. Créer un coupon

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
}
ChampObligatoireObjectif
list_betsOuiUn ou plusieurs pointeurs.
amountOuiLe montant positif d’un coupon en cours de création.
currencyNonToute désignation de chaîne, y compris la monnaie virtuelle.
callback_urlNonRappel d’URL ; sans rappel, vous ne pouvez pas l’envoyer, vous pouvez transmettre null, une chaîne vide ou un domaine de site.
langNonUn code à deux lettres pour l’une des 50 langues environ prises en charge. Le langage des noms est fixé lors de la création.
modeNonreject ou accept ; par défaut reject.
mode_typePour acceptDirection admissible du changement de coefficient.
multiNonUn coupon général ou individuel simple ; par défaut false.

Chances

ParamètresComportement
mode = rejectRejeter la création lorsque le coefficient change.
mode = accept, mode_type = 1Acceptez uniquement les promotions.
mode = accept, mode_type = 2Acceptez uniquement la rétrogradation.
mode = accept, mode_type = 3Acceptez tout changement.

Ordinaire, express et multi

DemandeRésultatRadiation du solde du client
Un résultatUn ordinaireamount
Résultats multiples, multi = falseUn expressamount
Résultats multiples, multi = trueSéparé unique pour chaque résultatamount × nombre de coupons créés

Un train express ne peut contenir plus de 15 événements. Vous ne pouvez pas combiner plusieurs paris sur le même match, y compris le match principal, les mi-temps, les périodes, les corners, les fautes et autres sous-événements associés. Cette combinaison renvoie 506.

6. Confirmation du coupon et création de l'offre

Réponse complète réussie avec coupon et données de pari acceptés dans 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"
}

Champs de coupons

Chaque article body.coupons[] est un coupon distinct créé.

ChampTapezSignification
coupon_codestringCode promo public à 12 chiffres. Stockez sous forme de chaîne pour éviter de perdre les zéros non significatifs.
amountnumberLe montant du coupon transféré lors de la création.
winnumberMontant gagnant actuellement affiché.
potential_winnumberGains possibles avant règlement définitif.
real_winnumber/nullMontant réel du paiement après calcul ; avant calcul - null.
coefnumberRatio du coupon actuel ou final.
original_coefnumberLe coefficient total du coupon au moment de sa création.
calculate_coefnumber/nullCoefficient calculé final ; avant calcul - null.
has_returnbooleantrue, si le coupon contient un pari avec un statut de remboursement.
dateintegerDate de création du coupon, horodatage Unix en millisecondes.
statusintegerStatut actuel du coupon. Les valeurs sont décrites dans la section « Statut du coupon et de l’enchère ».
asianbooleanSigne de la présence d’un règlement asiatique, comprenant la moitié des gains ou des pertes.
calculate_dateinteger/nullDate de calcul du coupon en millisecondes ; avant calcul - null.
coupon_typeintegerType de coupon : 1 - ordinaire, 2 - express.
events_countintegerNombre de paris à l’intérieur du coupon.
events_dataarrayLa gamme complète de paris inclus dans le coupon.

Champs d’enchères

Chaque élément de events_data[] décrit un pari spécifique accepté dans le coupon.

ChampTapezSignification
idinteger/nullID interne du pari accepté. Utilisé conjointement avec coupon_code pour rechercher un tarif dans un coupon.
game_idintegerID de l’événement ou du sous-événement sur lequel le pari est placé.
main_game_idinteger/nullID du match principal auquel appartient l’événement ou le sous-événement.
is_sub_gamebooleantrue, si le pari concerne une mi-temps, une période, un set, des corners ou tout autre sous-événement.
parent_game_idinteger/nullL’ID de l’événement parent immédiat, s’il existe.
sub_game_keystring/nullClé technique d’un sous-événement ou d’une période.
raw_pointerstringL’indicateur de taux d’origine accepté par l’API.
line_typestringType de ligne : line - pré-match, live - événement en temps réel.
is_livebooleantrue, si le pari a été créé sur une ligne en direct.
bet_group_idintegerID du groupe de paris ou du marché.
bet_group_namestring/nullNom localisé du groupe de pari.
bet_idintegerID de la sélection sélectionnée au sein du groupe de paris.
bet_namestring/nullNom complet localisé de la sélection sélectionnée.
sport_idinteger/nullCarte d’identité sportive.
sport_namestring/nullNom localisé du sport.
tournament_idinteger/nullIdentifiant du tournoi.
tournamentstring/nullNom localisé du tournoi.
event_dateinteger/nullDate de début de l’événement, horodatage Unix en millisecondes.
statusintegerÉtat actuel du calcul du taux. A ne pas confondre avec le statut du coupon.
opp1string/nullNom de la première équipe ou participant.
opp2string/nullNom de la deuxième équipe ou participant.
coefnumberLa cote du pari à laquelle le pari a été accepté.
calc_coefnumber/nullMultiplicateur de pari calculé ; avant calcul - null.
bet_scorestringChamp compatible avec l’API héritée contenant l’indicateur de pari plutôt que le score du match.
calculate_dateinteger/nullDate de calcul du taux en millisecondes ; avant calcul - null.
calculate_scorestring/nullLe compte utilisé pour calculer le pari.
settlement_reason_codestring/nullCode machine stable du motif du paiement ou du retour ; avant calcul - null.
settlement_reasonstring/nullTexte explicatif du motif du paiement ou du retour ; avant calcul - null.
placement_score_fullstring/nullScore total de l’événement au moment de la création du pari, si disponible.
placement_score_periodsstring/nullScore par période au moment de la création du pari, si disponible.
calculation_score_fullstring/nullLe score total de l’événement au moment où le pari est réglé.
calculation_score_periodsstring/nullCompte par période au moment du calcul du taux.
timerinteger/nullMinuterie d’événement au moment de la sauvegarde des données, si disponible.
dop_namestring/nullNom du sous-événement : mi-temps, période, set, manche, etc.
ratestringParamètre de résultat, par exemple la valeur du total ou du handicap ; pour un résultat sans paramètre - "0".
sgame_idstring/nullClé étrangère de sous-événement.
game_numinteger/nullNuméro de jeu, si fourni par la source.
stat_idstring/nullID d’événement statistique externe.
team1_idinteger/nullID de la première équipe ou participant.
team2_idinteger/nullID de la deuxième équipe ou participant.
opp_icon1integer/nullID compatible de la première icône de commande ; correspond à team1_id.
opp_icon2integer/nullID d’icône de deuxième équipe compatible ; correspond à team2_id.

La valeur null est normale pour les données qui n’ont pas encore été calculées ou qui ne sont pas disponibles. Ne le remplacez pas automatiquement par 0 ou la chaîne vide.

Considérez le coupon accepté uniquement si code = 1 et la présence d’objets dans body.coupons. Avant cela, le panier est un choix préliminaire : la sélection peut disparaître, être bloquée ou les cotes changer.

Après succès :

  1. enregistrez tous les objets body.coupons, pas seulement le premier ;
  2. stocker coupon_code sous forme de chaîne avec des zéros non significatifs ;
  3. enregistrez les données requises à partir de events_data ;
  4. faire correspondre le coupon à l’utilisateur final ;
  5. enregistrer la transaction financière de l’utilisateur dans le système du partenaire.

Identifiants :

ChampObjectif
coupon_codeCode de réduction public.
events_data[].idID du pari spécifique accepté à l’intérieur du coupon.
rappel events_data[].uuidLe même identifiant d’enchère, transmis sous forme de chaîne.
batchIdID de la version du package de rappel, pas du coupon ou du tarif.

currency n’est pas renvoyé dans le modèle complet et le rappel. Si la devise est nécessaire, enregistrez la valeur de la demande de création.

7. Erreurs de création

CoderRaisonAction
10Aucun corps de requête.Corrigez la demande.
11Pointeur invalide.Obtenez le pointeur actuel de la ligne.
12amount non valide.Passez un nombre positif.
501Le coefficient a changé.Afficher une nouvelle valeur ou modifier mode.
502Il n’y a pas de résultat.Supprimer/mettre à jour l’enchère dans le panier.
503Le résultat est bloqué.Signaler une indisponibilité temporaire.
504Erreur de vérification du résultat.Ne considérez pas le coupon comme accepté ; répéter plus tard.
506Dans les paris express, un match.Laissez un résultat ou utilisez des singles séparés.
507Solde client insuffisant.Rechargez votre solde ou réduisez le montant total.
1002Jeu de paramètres invalide.Paramètres corrects.
10000Erreur interne.Enregistrez l’erreur et vérifiez le résultat avant de réessayer.

Pour 501 à 504, la nouvelle API renvoie les taux problématiques dans body.changes[]. Champ change_type : 1 - le coefficient a augmenté, 2 - a diminué, null - la direction n’est pas applicable.

Ne réessayez pas aveuglément POST /coupons/place après l’expiration du délai : la première demande a peut-être été acceptée et une nouvelle tentative créera un doublon.

8. Réception de coupons

FonctionnementPoint de terminaisonRésultat
Un couponGET /api/partner/coupons/get?coupon_code={code}Coupon à body.
ActifGET /api/partner/coupons/activeTableau dans body[].
Calculs récentsGET /api/partner/coupons/calculated?time=10Tableau dans body[] ; maximum 120 minutes.
Par code/périodePOST /api/partner/coupons/resultsTableau dans body.coupons.
Solde clientGET /api/partner/balancebody.balance.

Vous pouvez transférer jusqu’à 100 valeurs à l’aide de codes :

{
  "coupon_ids": ["000000000272", "000000000273"]
}

Ou ne dépassez pas la période de création de 24 heures :

{
  "start_date": 1784880000000,
  "end_date": 1784966400000
}

Ne combinez pas coupon_ids et les dates dans la même requête. results filtre par heure de création et calculated filtre par heure de règlement final.

9. Statuts des coupons et des paris

Statuts des coupons :

CoderSignificationFinale
0Actif ou partiellement réglé.Non
2Gagné.Oui
4Perdu.Oui
8Entièrement remboursé.Oui
15Renvoyé pour recalcul ; attendez-vous à un nouveau résultat.Non

Statuts des offres :

CoderSignificationcalc_coef
0Non calculé.null
1Gagner.Coefficient d’origine
2Perdre.0
3Retour.1
4En attente de recalcul.null
21La moitié des gains.(coef + 1) / 2
22Demi-perte.0.5
23Poussez.1

Pour l’accumulation financière pour l’utilisateur final, utilisez le real_win prêt à l’emploi. N’utilisez pas potential_win et ne recalculez pas le paiement vous-même. Avant le calcul, real_win, calculate_coef, calc_coef et calculate_date sont égaux à null, et non à 0.

Au premier statut du coupon 15, si le résultat précédent a déjà été traité financièrement, le partenaire débite à nouveau le amount à l’utilisateur final, attend un nouveau statut final et facture un nouveau real_win. Protéger les opérations du retraitement.

10. Raison du calcul

Chaque pari dans le modèle complet et rappel a :

ChampObjectif
settlement_reason_codeCode de motif de paiement/remboursement stable.
settlement_reasonTexte source explicatif.

Avant calcul, les deux champs sont égaux à null. Pour une notification localisée, utilisez un code tel que :

  • MATCH_POSTPONED - le match a été reporté ;
  • MATCH_CANCELLED - match annulé ;
  • MARKET_PUSH - retour selon les règles du marché.

Si le code est inconnu, enregistrez-le et utilisez le settlement_reason non vide comme texte de secours. Ne calculez pas le paiement par motif - utilisez les statuts et real_win.

Ces champs expliquent le calcul ou le retour qui a déjà été effectué et ne constituent pas un flux distinct en temps réel de l’état de la correspondance.

11. Rappel

Le rappel est facultatif. Un partenaire ne peut travailler que par sondage. Pour le rappel, le gestionnaire doit activer la fonction et créer callback_secret ; L’URL est envoyée dans chaque coupon créé.

Le partenaire détermine indépendamment l’URL de rappel. En production, il doit utiliser https:// ; dans un environnement de test, http:// est autorisé.

Le système envoie :

POST {callback_url}
Content-Type: application/json
X-Coupon-Signature: sha256=<hex_hmac_sha256>

Charge utile courte :

{
  "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
        }
      ]
    }
  ]
}

Règles obligatoires :

  1. calculer sha256=<hex(HMAC-SHA256(raw_body, callback_secret))> à partir des octets sources exacts du corps avant l’analyse JSON et comparer les signatures de manière sécurisée ;
  2. traiter tous les articles coupons, le colis peut contenir jusqu’à 100 coupons ;
  3. stocker batchId avec un index unique ;
  4. le batchId répété ne doit pas répéter la radiation ou l’accumulation ;
  5. un coupon_code peut être accompagné de différents batchId lors du calcul et du recalcul progressifs ;
  6. renvoie HTTP 200 uniquement une fois que l’intégralité du paquet a été stockée en toute sécurité.

La réponse réussie minimale est un HTTP 200 vide. Avancé :

{
  "success": true,
  "processed": 1
}

processed doit être égal à couponCount. Les réponses 201, 202 et 204 ne sont pas considérées comme réussies.

Les replays sont effectués uniquement en cas de timeout, d’erreur de transport ou HTTP 500, 502, 503, 504 : immédiatement, puis après 1, 5, 15 et 60 minutes - pas plus de cinq envois. Il n’y a pas de nouvelle tentative automatique sur HTTP 200 avec success: false ou processed partielle.

12. Sondage de réserve

Même avec rappel, vérifiez périodiquement les résultats :

GET /api/partner/coupons/calculated?time=10

Après une pause de plus de 120 minutes, utilisez POST /api/partner/coupons/results sur le coupon_ids enregistré ou sur des périodes de création allant jusqu’à 24 heures. Recevoir la même fortune ne doit pas répéter les transactions financières.

13. Sécurité et stockage

  • stocker le login, le mot de passe, JWT et callback_secret uniquement sur le serveur ;
  • ne transmettez pas JWT dans l’URL et n’écrivez pas le jeton complet dans les journaux ;
  • utilisez le type décimal pour l’argent ;
  • stocker coupon_code sous forme de chaîne ;
  • enregistrer amount, les données d’offre requises et currency, le cas échéant ;
  • faire la distinction entre les statuts du coupon et de l’enchère ;
  • accepter les champs inconnus et les codes de raison sans erreur ;
  • Rendre idempotentes toutes les transactions financières des utilisateurs finaux.

14. Ancienne API et retrait

Les anciennes routes continuent d’être prises en charge, mais les nouvelles intégrations doivent utiliser /api/partner/**. Les anciennes réponses et erreurs ont des formats différents. Pour mettre à jour un client existant, utilisez un seul fichier « Migration depuis l’ancienne API ».

Cashout est en cours de développement, n’est pas entièrement testé et n’est pas recommandé pour la production.

15. Liste de contrôle finale

  • Reçu BASE_URL, login et mot de passe.
  • JWT est transmis sous forme de jeton Bearer.
  • Les pointeurs sont repris de la ligne sans modification.
  • Le panier n’est enregistré en tant que coupon accepté qu’après code = 1.
  • multi traité, restrictions expresses et erreurs 501507.
  • L’annulation automatique du solde client a été prise en compte.
  • Tous les coupon_code et les identifiants d’enchères sont enregistrés.
  • Le paiement final provient de real_win.
  • Le rappel est vérifié par rapport aux octets sources et dédupliqué à l’aide de batchId.
  • L’interrogation de sauvegarde a été configurée.
  • Le solde utilisateur est distinct du solde client SportAPI.

La documentation détaillée commence par Présentation de l’API. La carte complète des points de terminaison se trouve dans manuel.

Besoin de documentation supplémentaire ou d'aide à l'intégration ?