API Développeurs

Intégration POS
Dyno Wallet

Connectez votre terminal ou logiciel de caisse aux wallets Dyno. API REST sécurisée, sandbox incluse, deux flux de paiement.

OAuth2 Client CredentialsHMAC-SHA256ISO 27001TLS 1.3
Productionhttps://api.dyno-motiva.com
Sandboxhttps://sandbox.dyno-motiva.com

1. Authentification

OAuth2 Client Credentials — obtenez un Bearer token valide 1 heure.

POST/api/v1/pos/oauth/tokenPublic
{
  "grant_type": "client_credentials",
  "client_id":  "pos_client_abc123",
  "client_secret": "s3cr3t_xyz"
}
Réponse 200
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type":   "Bearer",
  "expires_in":   3600,
  "scope":        "payments"
}
ℹ️ Ajoutez Authorization: Bearer <token> à chaque requête. Le token sandbox contient le claim sandbox: true.
Flux A

Employee-Presented Mode (EPM)

L'employé génère un QR/NFC sur son app — le caissier scanne sur le terminal.

1
Employé ouvre l'app et génère un QR Code (TTL 30 secondes)
2
Le POS scanne le QR et soumet le payload + montant
3
Dyno répond de façon synchrone avec la confirmation
POST/api/v1/pos/payments/scan🔒 Bearer
{
  "qr_payload":      "eyJRclR5cGUiOiJ0cmFuc2FjdGlvbiIs...",
  "amount":          12.500,
  "pos_reference":   "CAISSE-01-TXN-20260604-001",
  "channel":         "qr"
}
Réponse 200 — Confirmée
{
  "transaction_id":    "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "status":            "succeeded",
  "amount":            12.500,
  "currency":          "TND",
  "wallet_type":       "TicketResto",
  "confirmation_code": "A1B2C3D4",
  "transaction_date":  "2026-06-05T10:30:00Z"
}
CodeSignification
410QR_EXPIRED — QR scanné après 30 secondes
413INSUFFICIENT_FUNDS — solde insuffisant
404MERCHANT_NOT_FOUND — commerçant non affilié
401Token Bearer absent ou expiré
Flux B

POS-Presented Mode (PPM)

Le POS génère la demande — l'employé scanne et confirme sur son app.

1
POS initie la session avec le montant
2
POS affiche le QR sur son écran (TTL 60s)
3
Employé scanne, choisit son wallet et confirme son PIN
4
Dyno notifie via webhook signé HMAC ou polling GET
POST/api/v1/pos/payments/initiate
{
  "amount":        45.000,
  "pos_reference": "CAISSE-01-SESS-007",
  "description":   "Déjeuner cafétéria",
  "channel":       "qr"
}
Réponse 200
{
  "payment_request_id": "7c9e6679-...",
  "qr_payload":  "iVBORw0KGgoAAAA...",
  "nfc_payload": "eyJTZXNzaW9uSWQi...",
  "amount":      45.000,
  "currency":    "TND",
  "expires_at":  "2026-06-05T10:31:00Z",
  "status":      "pending"
}
GET/api/v1/pos/payments/{id}/status
Polling fallback — 1 req/s, timeout 90s
StatutSignification
pendingEn attente de scan
scannedQR scanné, en cours
confirmedTransaction réussie
expiredTTL dépassé
failedErreur (solde, PIN…)
cancelledAnnulé par l'employé

Webhooks — Confirmation Flux B

Dyno envoie un HTTP POST signé vers l'URL configurée lors de la confirmation. Vérifiez la signature HMAC-SHA256 avant de traiter.

Headers reçus
X-Dyno-Webhook-Signature: sha256=a3f9b2...
Content-Type: application/json
Body
{
  "event":              "payment.confirmed",
  "payment_request_id": "7c9e6679-...",
  "transaction_id":     "3fa85f64-...",
  "amount":             45.000,
  "currency":           "TND",
  "status":             "succeeded",
  "pos_reference":      "CAISSE-01-SESS-007",
  "timestamp":          "2026-06-05T10:30:47Z"
}
Vérification HMAC-SHA256
expected = "sha256=" + HMAC_SHA256(webhook_secret, body)
if header != expected: reject (401)
🔁Retry policy : 3 tentatives avec backoff exponentiel (2s, 4s, 8s). Répondre HTTP 2xx pour acquitter.
⚠️ Si votre POS n'a pas d'IP publique, utilisez le polling GET /payments/{id}/status à la place.

Sandbox — Simulation de scénarios

Avec des credentials sandbox, ajoutez le header X-Dyno-Simulate pour déclencher n'importe quel scénario sans toucher aux données réelles.

X-Dyno-Simulate: success200

Transaction fictive réussie avec confirmation_code SANDBOX01

X-Dyno-Simulate: insufficient_funds413

INSUFFICIENT_FUNDS — solde insuffisant

X-Dyno-Simulate: expired_token410

QR_EXPIRED — QR présenté après 30 secondes

X-Dyno-Simulate: merchant_not_found404

MERCHANT_NOT_FOUND — commerçant non affilié

X-Dyno-Simulate: webhook_timeout200

ACK OK mais webhook simulé en timeout — teste votre fallback polling

Credentials Sandbox de démonstration

client_idpos_sandbox_demo
client_secretsandbox_secret_demo
webhook_secretsandbox_webhook_secret

Ces credentials sont en lecture seule et réinitialisés quotidiennement. Pour des credentials dédiés, contactez dev@dyno-motiva.com.

Sécurité

🔐

TLS 1.3

Toutes les communications sont chiffrées. HTTP non accepté.

🎫

JWT Signé

Token HMAC-SHA256, durée de vie 1 heure, révocation instantanée.

🔏

Webhooks Signés

Signature HMAC-SHA256 sur chaque payload. Rejetez sans vérification.

⏱️

Rate Limiting

60 requêtes / minute par client_id. Dépassement → 429 Too Many Requests.

🛡️

ISO 27001 Ready

Infrastructure conforme. Logs d'audit conservés 12 mois.

🔑

Secrets Manager

Aucun secret en clair. Rotation automatique via AWS Secrets Manager.

Prêt à intégrer Dyno ?

Testez en sandbox dès maintenant, sans engagement. Obtenez vos credentials de production en 24h.