API REST

Toute la plateforme est pilotable par API

Chaque écran de fastergateway s’appuie sur cette API : connecteurs, routes, filtres, campagnes, contacts, soldes, accusés de réception. La référence ci-dessous est extraite du code du backend, pas rédigée à côté — elle ne peut donc pas dériver.

https://demo.fastergateway.net:3002/api/v1v1.0 · 172 opérations

Avant le premier appel

Quatre repères qui valent pour toutes les routes

Le reste se lit dans la référence.

Authentification

POST /api/v1/auth/login rend un jeton JWT et un jeton de rafraîchissement. Les routes marquées d’un cadenas attendent l’en-tête Authorization: Bearer.

Débit

10 requêtes par seconde et par adresse IP. Au-delà, la réponse est un 429 : le client doit réessayer plus tard, pas insister.

Enveloppe de réponse

Toujours la même forme, { success, data, error }, avec le code HTTP correspondant. Une erreur ne rend jamais 200.

Accusés de réception

La passerelle rappelle /api/v1/sms/dlr/gateway. Le DLR est ensuite embarqué dans le message et se relit par l’API des messages.

Secrets en transit

Chiffrer les mots de passe, si vous le voulez

Facultatif et par appelant : le backend regarde le champ et décide seul. Préfixe reconnu, il déchiffre ; autre chose, il prend la valeur telle quelle. Aucune requête existante ne change.

La clé

Remise en main propre par l’exploitant. Elle ne circule pas par l’API, ne se met pas dans un navigateur — un bundle JavaScript se lit —, et ne sert qu’au transport.

Format attendu

enc:v1:<iv>:<tag>:<chiffré>

AES-256-GCM · iv 12 octets · tag 16 octets · les trois en base64

Node 20+

import { createCipheriv, randomBytes } from 'node:crypto';

const CLE = Buffer.from(process.env.SECRETS_KEY, 'base64');

export function chiffrer(clair) {
  const iv = randomBytes(12);
  const c = createCipheriv('aes-256-gcm', CLE, iv);
  const corps = Buffer.concat([c.update(clair, 'utf8'), c.final()]);
  return [
    'enc:v1:' + iv.toString('base64'),
    c.getAuthTag().toString('base64'),
    corps.toString('base64'),
  ].join(':');
}

// await fetch(url, { method: 'POST', headers, body: JSON.stringify({
//   uid: 'FAST_1234', gid: 'grp_8', username: 'client',
//   password: chiffrer('MonSecret9'),
// })});

Python 3 · cryptography

import base64, os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

CLE = base64.b64decode(os.environ["SECRETS_KEY"])

def chiffrer(clair: str) -> str:
    iv = os.urandom(12)
    # AESGCM.encrypt colle le tag (16 octets) A LA FIN du chiffre :
    # il faut l'en detacher, le format attendant les deux separement.
    sortie = AESGCM(CLE).encrypt(iv, clair.encode(), None)
    corps, tag = sortie[:-16], sortie[-16:]
    b = lambda x: base64.b64encode(x).decode()
    return f"enc:v1:{b(iv)}:{b(tag)}:{b(corps)}"

Champs acceptant un secret chiffré

  • /auth/login · /auth/signup · /auth/reset-passwordpassword
  • /users · /users/{id}password
  • /jasmin-users · /jasmin-users/{uid}password
  • /gateways · /gateways/{id}password
  • /smpp-connectors · /smpp-connectors/{cid}password
  • /bridges · /bridges/{id}bindPassword, authValue

Ce que cela ferme n’est pas l’interception — TLS s’en charge déjà — mais la trace qu’un mot de passe en clair laisse derrière lui : le journal d’un proxy, une capture interne, un rapport d’erreur. La protection vaut ce que vaut le secret de la clé.

Référence

Toutes les routes du backend

Groupées par domaine, telles que le serveur les expose.

172 opérations