Documentation développeur

Guide complet pour intégrer les APIs SIFIP : authentification, appel des endpoints, gestion des erreurs, exemples Python et cURL.

Introduction

L'API SIFIP est une API REST sécurisée par OAuth2 (Bearer JWT). Toutes les requêtes utilisent https://api.sifip.io (ou http://api.localtest.me en dev local).

Chaque appel est facturé selon votre offre (forfait ou paiement à l'usage). Les réponses sont au format JSON avec Content-Type: application/json.

Conformité. Nos APIs suivent les standards de l'industrie télécom (compatibilité ascendante garantie pour la version 1.x).

Prérequis

  1. Créez un compte partenaire (gratuit, 1 minute).
  2. Connectez-vous et créez une application dans votre dashboard.
  3. Récupérez votre clé privée RSA 2048 (affichée une seule fois, sauvegardez-la).
  4. Souscrivez à une offre commerciale qui couvre les APIs souhaitées.

Choisir une offre

Standard

Number Verification, KYC Tenure, SIM Swap. Idéal pour onboarding.

99 €/mois ou 0.03 €/appel

Pro

Standard + Device Swap, Number Recycling, Call Forwarding, Verified Caller.

499 €/mois ou 0.02 €/appel

Premium

Pro + Fraud Engine (scoring consolidé).

2 500 €/mois ou 0.015 €/appel

Unitaire

Une seule API. PAYG entre 0.03 € et 0.10 €/appel selon l'API.

Voir les tarifs unitaires →

Flux d'authentification OAuth2

SIFIP utilise le flow client_credentials avec Private Key JWT (RFC 7523). Aucun secret partagé n'est transmis : votre application signe une assertion JWT avec sa clé privée RSA.

  1. Votre application signe une assertion JWT (RS256) avec sa clé privée.
  2. Elle l'envoie au token endpoint Keycloak.
  3. Keycloak vérifie la signature (avec la clé publique enregistrée) et émet un access token.
  4. Votre application utilise ce token (Bearer) pour appeler les APIs SIFIP.
L'access token est valide 15 minutes. Rafraîchissez-le avant expiration (pas de refresh_token en client_credentials).

Clés privées RSA

Lors de la création de votre application sur le portail SIFIP, une paire de clés RSA 2048 est générée. La clé privée vous est affichée une seule fois au format PEM (PKCS#8). Sauvegardez-la dans un coffre fort (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, etc.).

-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQ...
...
-----END PRIVATE KEY-----

Sécurité : ne loggez jamais la clé privée, ne la commitez pas en git, ne l'envoyez jamais par email. Si elle est compromise, supprimez l'application et créez en une nouvelle.

Obtenir un access token

Étape 1 : générer l'assertion JWT

Construisez un JWT signé RS256 avec les claims suivants :

{
  "iss": "votre-client-id",
  "sub": "votre-client-id",
  "aud": "https://auth.sifip.io/realms/sifip/protocol/openid-connect/token",
  "jti": "uuid-unique-par-requête",
  "exp": "now + 60 secondes",
  "iat": "now"
}

Étape 2 : échanger l'assertion contre un access token

POST https://auth.sifip.io/realms/sifip/protocol/openid-connect/token avec Content-Type: application/x-www-form-urlencoded :

grant_type=client_credentials
&client_id=votre-client-id
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<JWT signé ci-dessus>
&scope=sifip:sim-swap

Réponse

{
  "access_token": "eyJhbGc...",
  "expires_in": 900,
  "token_type": "Bearer",
  "scope": "sifip:sim-swap"
}

Exemple complet en Python

import time, uuid, jwt, requests

CLIENT_ID    = "sifip-app-mybank-abc123"
PRIVATE_KEY  = open("private.pem").read()
TOKEN_URL    = "https://auth.sifip.io/realms/sifip/protocol/openid-connect/token"

now = int(time.time())
assertion = jwt.encode({
    "iss": CLIENT_ID, "sub": CLIENT_ID,
    "aud": TOKEN_URL,
    "jti": str(uuid.uuid4()),
    "exp": now + 60, "iat": now,
}, PRIVATE_KEY, algorithm="RS256")

r = requests.post(TOKEN_URL, data={
    "grant_type": "client_credentials",
    "client_id": CLIENT_ID,
    "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
    "client_assertion": assertion,
    "scope": "sifip:sim-swap"
})
access_token = r.json()["access_token"]

Appeler une API SIFIP

Avec l'access token, appelez les APIs avec le header Authorization: Bearer <token> :

r = requests.post(
  "https://api.sifip.io/sim-swap/vwip/check",
  headers={
    "Authorization": f"Bearer {access_token}",
    "Content-Type": "application/json",
    "X-Request-ID": str(uuid.uuid4())  # optionnel mais recommandé pour tracer
  },
  json={"phoneNumber": "+261340000000", "maxAge": 240}
)
print(r.json())  # {"swapped": false}

L'en-tête X-Request-ID est propagé dans nos logs et facilite le support en cas d'incident.

SIM Swap

Détecte si la SIM associée à un MSISDN a été échangée récemment (red flag fraude).

Scope requis : sifip:sim-swap

POST /sim-swap/vwip/retrieve-date

Date du dernier SIM swap.

{ "phoneNumber": "+261340000000" }
↓
{ "latestSimChange": "2026-04-15T10:23:00Z" }

POST /sim-swap/vwip/check

Booléen : SIM swap dans les maxAge heures ?

{ "phoneNumber": "+261340000000", "maxAge": 240 }
↓
{ "swapped": false }

Voir le swagger complet →

Number Verification

Vérifie que le MSISDN fourni correspond bien à celui de l'utilisateur (silent auth réseau).

Scope requis : sifip:number-verify

POST /number-verification/vwip/verify

{ "phoneNumber": "+261340000000" }
↓
{ "devicePhoneNumberVerified": true }

GET /number-verification/vwip/device-phone-number

Renvoie le MSISDN du device authentifié.

{ "devicePhoneNumber": "+261340000000" }

Voir le swagger complet →

KYC Tenure

Vérifie qu'un abonné est client de l'opérateur depuis au moins une date donnée (signal fort de confiance).

Scope requis : sifip:identity

POST /kyc-tenure/vwip/check-tenure

{ "phoneNumber": "+261340000000", "tenureDate": "2023-01-01" }
↓
{ "tenureDateCheck": true, "contractType": "PAYM" }

Voir le swagger complet →

Device Swap

Détecte un changement récent de device (IMEI) sur le même MSISDN.

Scope requis : sifip:device-swap

POST /device-swap/vwip/retrieve-date

{ "phoneNumber": "+261340000000" }
↓
{ "latestDeviceChange": "2026-03-22T08:15:00Z" }

POST /device-swap/vwip/check

{ "phoneNumber": "+261340000000", "maxAge": 240 }
↓
{ "swapped": false }

Voir le swagger complet →

Number Recycling

Détecte si le titulaire d'un numéro a changé depuis une date donnée (évite d'envoyer des SMS à un nouveau titulaire).

Scope requis : sifip:number-recycling

POST /number-recycling/vwip/check

{ "phoneNumber": "+261340000000", "specifiedDate": "2024-10-31" }
↓
{ "phoneNumberRecycled": false }

Voir le swagger complet →

Call Forwarding Signal

Détecte si un service de call forwarding est actif (red flag pour interception OTP).

Scope requis : sifip:call-forwarding

POST /call-forwarding-signal/vwip/unconditional-call-forwardings

{ "phoneNumber": "+261340000000" }
↓
{ "active": false }

POST /call-forwarding-signal/vwip/call-forwardings

{ "phoneNumber": "+261340000000" }
↓
["inactive"]   // ou ["unconditional","conditional_busy"]

Voir le swagger complet →

Verified Caller

Crée une pré-annonce d'appel sortant (anti-spoofing) avec affichage de marque chez le destinataire.

Scope requis : sifip:verified-caller

POST /verified-caller/vwip/pre-announce

{
  "callingParticipant": "+261340000000",
  "calledParticipant":  "+261349999999",
  "strategy": "BRAND_DISPLAY",
  "timeToLive": 60,
  "dynamicDisplayName": "ACME Bank"
}
↓ 201 Created
{ "preAnnouncementId": "uuid", "expiresAt": "2026-05-25T10:00:00Z" }

Voir le swagger complet →

Fraud Engine

Scoring consolidé multi-signaux (telco + device + biométrie + comportemental + géo). Renvoie une décision APPROVE / REVIEW / CHALLENGE / REJECT.

Scope requis : sifip:fraud-engine

POST /fraud-engine/score

{
  "transactionId": "txn-987654",
  "useCase": "PAYMENT",
  "customer": { "firstName": "Ali", "lastName": "Rahal" },
  "telecom":  { "msisdn": "+216 55111222", "simSwap": { "enabled": true } },
  "device":   { "ipAddress": "1.2.3.4", "rooted": false, "emulator": false },
  "biometrics": { "livenessScore": 0.95, "deepfakeProbability": 0.02 },
  "behavioral": { "typingSpeed": 215, "abnormalNavigation": false }
}
↓
{
  "decision": "APPROVE",
  "riskLevel": "LOW",
  "scores": {
    "fraudScore": 12,
    "identityConfidenceScore": 94,
    "telecomTrustScore": 91,
    "biometricTrustScore": 97,
    "deviceTrustScore": 89
  },
  "riskSignals": ["VALID_MSISDN","KNOWN_DEVICE","BIOMETRIC_MATCH"],
  "recommendation": { "action": "ALLOW", "stepUpAuthentication": false }
}

Voir le swagger complet →

Codes d'erreur

Code HTTPCode SIFIPDescriptionComment résoudre
400INVALID_ARGUMENTBody JSON malformé ou paramètre invalideVérifier le format selon le swagger
400OUT_OF_RANGEValeur hors plage (ex. maxAge > 2400h)Réduire la valeur
401UNAUTHENTICATEDToken absent, expiré ou signature invalideObtenir un nouveau token
401token revokedToken révoqué via /admin/tokens/revokeObtenir un nouveau token (jti différent)
403PERMISSION_DENIEDToken valide mais scope insuffisantSouscrire à une offre qui inclut le scope requis
404NOT_FOUNDRessource ou identifier inconnuVérifier le clientId / phoneNumber
404IDENTIFIER_NOT_FOUNDMSISDN non reconnu par l'opérateurVérifier le format E.164 et l'opérateur
422SERVICE_NOT_APPLICABLEAPI non disponible pour ce MSISDNOpérateur non supporté pour cette API
422MISSING_IDENTIFIERphoneNumber manquant (2-legged)Ajouter phoneNumber dans le body
422UNNECESSARY_IDENTIFIERphoneNumber fourni en 3-leggedNe pas fournir phoneNumber (déjà dans le token)
429QUOTA_EXCEEDEDQuota mensuel atteintUpgrade d'offre
429TOO_MANY_REQUESTSRate limit gateway dépasséBackoff exponentiel et retry
500INTERNALErreur serveur SIFIPRéessayer après quelques secondes, contacter le support si persistant
503UNAVAILABLEMaintenance temporaireAttendre, voir status.sifip.io

Format de réponse d'erreur

{
  "status":  400,
  "code":   "INVALID_ARGUMENT",
  "message": "Client specified an invalid argument, request body or query param."
}

Rate limiting

Chaque appel API renvoie 3 en-têtes :

  • X-RateLimit-Limit : limite par minute selon votre offre
  • X-RateLimit-Remaining : appels restants dans la fenêtre courante
  • X-RateLimit-Reset : secondes restantes avant reset

Limites par offre :

Offrereq/min
Unitaire60
Standard100
Pro300
Premium1 000

Sandbox vs Production

Deux environnements sont disponibles :

EnvURLDonnéesFacturation
Sandboxhttps://sandbox-api.sifip.ioStub (random)Aucune
Productionhttps://api.sifip.ioRéelles (via opérateurs)Selon offre

Vos clientId et clé privée sont les mêmes dans les deux environnements. Le scope est aussi identique.