REST API
Every part of the platform is driveable over the API
Every fastergateway screen sits on this API: connectors, routes, filters, campaigns, contacts, balances, delivery receipts. The reference below is extracted from the backend source rather than written alongside it, so it cannot drift.
https://demo.fastergateway.net:3002/api/v1v1.0 · 172 operationsBefore the first call
Four things that hold for every route
The rest is in the reference.
Authentication
POST /api/v1/auth/login returns a JWT and a refresh token. Routes marked with a padlock expect the Authorization: Bearer header.
Rate limit
10 requests per second per IP address. Past that the answer is a 429: the client should back off rather than push.
Response envelope
Always the same shape, { success, data, error }, with the matching HTTP status. An error never comes back as a 200.
Delivery receipts
The gateway calls back /api/v1/sms/dlr/gateway. The DLR is then embedded in the message and read back through the messages API.
Secrets in transit
Encrypt passwords, if you want to
Optional and per caller: the backend looks at the field and decides on its own. Known prefix, it decrypts; anything else, it takes the value as is. No existing request changes.
The key
Handed over directly by the operator. It never travels through the API, never goes into a browser — a JavaScript bundle can be read — and serves transport only.
Expected format
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)}"Fields accepting an encrypted secret
/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
What this closes is not interception — TLS already covers that — but the trail a cleartext password leaves behind: a proxy log, an internal capture, an error report. The protection is worth exactly what the key’s secrecy is worth.
Reference
Every backend route
Grouped by domain, exactly as the server exposes them.
172 operations