API REST v1

Documentation développeur

Intégrez les notifications push Android, iOS et Web en quelques minutes avec notre API REST simple et sécurisée.

Introduction

SoftAfrik Push est une plateforme SaaS de notifications push destinée au marché africain. Elle prend en charge :

  • Android via Firebase Cloud Messaging (FCM) HTTP v1
  • iOS via Apple Push Notification Service (APNS)
  • Web Push via FCM

Toutes les requêtes API (sauf les URLs de tracking publiques) nécessitent une clé API passée dans le header X-API-Key.

La clé API ne doit JAMAIS être exposée dans du JavaScript frontend. Elle doit rester exclusivement côté backend.

Authentification

Toutes les requêtes API doivent inclure l'en-tête suivant :

Content-Type: application/json
X-API-Key: sk_live_votre_cle_api_ici
Obtenir une clé API
  1. Créez un compte sur SoftAfrik Push
  2. Connectez-vous au dashboard client ou admin
  3. Générez ou copiez votre clé API (64 caractères hexadécimaux)
Sécurité
  • La clé est liée à un api_client_id unique
  • Le client doit avoir le statut active
  • Un client soft-deleted est rejeté

Base URL

https://push.softafrik.com/api/v1

En développement local (Docker) :

http://localhost:8080/api/v1

Formats & Erreurs

Réponse succès (HTTP 200)
{
  "success": true,
  "message": "Push created successfully",
  "data": { ... }
}
Réponse erreur
{
  "success": false,
  "error": "title and message are required",
  "details": { ... }
}
Codes HTTP courants
HTTPCause
200Succès
400Requête invalide (paramètres manquants ou incorrects)
401Authentification échouée (clé API manquante, invalide ou suspendue)
404Ressource introuvable
429Rate limit ou quota dépassé
500Erreur serveur (FCM, base de données, etc.)

Quota & Santé API

GET /quota

Vérifie la santé de l'API, les limites de votre plan et la consommation actuelle.

Réponse (200)
{
  "success": true,
  "message": "OK",
  "data": {
    "plan": { "code": "pro", "name": "Pro" },
    "limits": {
      "devices": 50000,
      "pushes_per_month": 500000,
      "api_requests_per_minute": 1000
    },
    "current_month": {
      "devices_count": 12,
      "pushes_sent": 340,
      "api_requests": 1200
    },
    "totals": {
      "active_devices": 45,
      "total_pushes": 1280
    }
  }
}
GET /health Public

Health check public (pas d'authentification requise).

{ "success": true, "message": "OK", "timestamp": "2026-05-02T13:17:50+00:00" }

Devices

POST /devices

Enregistre ou met à jour un device (upsert par push_token).

Payload
ChampTypeRequisDescription
push_tokenstringToken FCM ou APNS
platformstringandroid, ios ou web
external_user_idstringID utilisateur côté client
emailstringEmail utilisateur
phonestringTéléphone
countrystringCode ISO-3166 alpha-2 (ex: CI, TG, BJ)
languagestringLangue (défaut fr)
device_modelstringModèle de l'appareil
browserstringNavigateur
user_agentstringUser-Agent
timezonestringFuseau horaire
permission_statusstringStatut permission notif
os_versionstringVersion OS
app_versionstringVersion app
metadataobjectJSON libre
Exemple
{
  "push_token": "dGhpcyBpcyBhIGZha2UgdG9rZW4...",
  "platform": "web",
  "external_user_id": "customer_12345",
  "email": "client@example.com",
  "phone": "+22897417951",
  "country": "TG",
  "language": "fr",
  "device_model": "Chrome Desktop",
  "os_version": "Windows 11",
  "app_version": "1.0.0"
}
Réponse
{
  "success": true,
  "message": "Device registered",
  "data": { "device_id": 123, "platform": "web", "token_status": "valid" }
}
GET /devices?page=1&platform=web&status=valid&country=TG

Liste les devices avec pagination et filtres.

Réponse
{
  "success": true,
  "message": "OK",
  "data": {
    "devices": [
      {
        "id": 123,
        "platform": "web",
        "push_token": "dGhpcyBpcyBhIGZha2UgdG9rZW4...",
        "token_status": "valid",
        "external_user_id": "customer_12345",
        "last_active_at": "2026-04-25 14:30:00",
        "created_at": "2026-04-20 10:00:00"
      }
    ],
    "pagination": {
      "total": 45,
      "per_page": 20,
      "current_page": 1,
      "last_page": 3
    }
  }
}
PUT /devices/{id}

Met à jour un device. Champs acceptés : device_model, language, country, token_status.

{
  "device_model": "Chrome 124",
  "language": "fr",
  "country": "TG",
  "token_status": "valid"
}
DELETE /devices/{id}

Révoque un device (soft delete). Le token_status passe à revoked.

{
  "success": true,
  "message": "Device revoked",
  "data": { "device_id": 123 }
}

Push / Notifications

POST /push/send

Crée une notification push et la met en file d'attente pour envoi asynchrone.

Payload
ChampTypeRequisDescription
titlestringTitre de la notification
messagestringCorps de la notification
target_typestringall (défaut), segment, device_ids, external_user_id
target_valuemixedPlateforme, IDs ou PUID selon target_type
image_urlstringURL image
action_urlstringURL ou deep link au clic
custom_dataobjectDonnées JSON libres transmises au device
scheduled_atstringPlanification YYYY-MM-DD HH:MM:SS
Exemple — Envoi à tous
{
  "title": "Nouvelle promo !",
  "message": "Profitez de -30% sur tous les articles",
  "target_type": "all",
  "image_url": "https://cdn.example.com/banner.jpg",
  "action_url": "https://example.com/promos/summer",
  "custom_data": { "promo_id": 42, "expires": "2026-05-01" }
}
Exemple — Ciblage par external_user_id
{
  "title": "Commande confirmée",
  "message": "Votre commande #123 a été confirmée.",
  "target_type": "external_user_id",
  "target_value": "customer_12345",
  "action_url": "https://example.com/orders/123",
  "custom_data": { "order_reference": "ORD-123", "type": "order_status" }
}
Exemple — Ciblage par device IDs
{
  "title": "Message privé",
  "message": "Un vendeur vous a répondu.",
  "target_type": "device_ids",
  "target_value": [123, 124],
  "action_url": "https://example.com/messages/42"
}
Réponse
{
  "success": true,
  "message": "Push created successfully",
  "data": {
    "push_id": 128,
    "recipients": 342,
    "status": "queued"
  }
}
GET /push/{id}/status

Consulte l'état agrégé d'un envoi (délivrés, ouverts, échoués, en attente).

{
  "success": true,
  "message": "OK",
  "data": {
    "push_id": 128,
    "title": "Nouvelle promo !",
    "status": "sent",
    "total_recipients": 342,
    "sent_at": "2026-04-25 20:00:00",
    "delivery": {
      "delivered": 320,
      "opened": 89,
      "failed": 22,
      "pending": 0
    }
  }
}

Campagnes

POST /campaigns

Crée une campagne structurée avec segmentation et planification.

Payload
ChampTypeRequisDescription
namestringNom interne
titlestringTitre du push
messagestringCorps du push
descriptionstringDescription interne
segment_criteriastringDéfaut all
platformstringandroid, ios, web
countrystringFiltre pays
image_urlstringImage
action_urlstringURL cible
scheduled_atstringPlanification
Exemple
{
  "name": "Campagne Ramadan 2026",
  "title": "Promo Ramadan",
  "message": "Des offres exceptionnelles pendant le mois béni",
  "platform": "android",
  "country": "CI",
  "scheduled_at": "2026-03-01 20:00:00"
}
Réponse
{
  "success": true,
  "message": "Campaign created",
  "data": {
    "campaign_id": 45,
    "push_id": 129,
    "recipients": 120,
    "status": "active"
  }
}
GET /campaigns

Liste les campagnes.

DELETE /campaigns/{id}

Annule une campagne.


Tracking

1. Tracking authentifié (backend)
POST /push/{id}/opened POST /push/{id}/clicked

Headers : X-API-Key + Content-Type: application/json

{ "device_id": 123 }
{ "success": true, "message": "Event tracked" }
2. URLs publiques signées (Service Worker)
GET /track/open?t=TOKEN&s=SIGNATURE Public

Tracking d'ouverture sans authentification. La signature HMAC-SHA256 garantit l'authenticité.

GET /api/v1/track/open?t=eyJ...&s=abc123
GET /track/click?t=TOKEN&s=SIGNATURE&redirect=URL Public

Tracking de clic avec redirection.

GET /api/v1/track/click?t=eyJ...&s=abc123&redirect=https%3A%2F%2Fexample.com
Dans le Service Worker
self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  const data = event.notification.data;
  fetch(data.tracking_url_click);
  event.waitUntil(clients.openWindow(data.action_url));
});

Webhooks

SoftAfrik Push peut notifier votre backend à chaque événement important. Configurez votre URL webhook dans le dashboard.

ÉvénementDéclencheur
push.createdCréation d'un push (avant envoi)
push.deliveredJob traité avec succès par le worker
push.failedJob échoué définitivement (dead letter)
Payload push.delivered
{
  "event": "push.delivered",
  "push_id": 128,
  "device_id": 123,
  "platform": "web",
  "status": "delivered",
  "timestamp": "2026-04-25T20:01:15+00:00"
}
Les webhooks sont envoyés en mode fire-and-forget avec un timeout de 10 secondes. Aucun retry automatique n'est implémenté pour l'instant.

Rate Limits & Quotas

Les limites dépendent de votre plan :

PlanDevicesPushes/moisRequêtes/min
Free1 00010 000100
Pro50 000500 0001 000
EnterpriseIllimitéIllimité10 000

En cas de dépassement, l'API renvoie HTTP 429 avec un message explicite.


Exemples cURL complets

1. Tester l'API (quota)
curl -s -X GET \
  -H "X-API-Key: sk_live_votre_cle_api" \
  "https://push.softafrik.com/api/v1/quota" | jq .
2. Enregistrer un device
curl -s -X POST \
  -H "X-API-Key: sk_live_votre_cle_api" \
  -H "Content-Type: application/json" \
  -d '{
    "push_token": "dGhpcyBpcyBhIGZha2UgdG9rZW4...",
    "platform": "web",
    "external_user_id": "customer_12345",
    "email": "client@example.com",
    "phone": "+22897417951",
    "country": "TG",
    "language": "fr"
  }' \
  "https://push.softafrik.com/api/v1/devices" | jq .
3. Envoyer un push (tous)
curl -s -X POST \
  -H "X-API-Key: sk_live_votre_cle_api" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Nouvelle promo !",
    "message": "Profitez de -30% sur tous les articles",
    "target_type": "all",
    "image_url": "https://cdn.example.com/banner.jpg",
    "action_url": "https://example.com/promos/summer",
    "custom_data": { "promo_id": 42 }
  }' \
  "https://push.softafrik.com/api/v1/push/send" | jq .
4. Statut d'un push
curl -s -X GET \
  -H "X-API-Key: sk_live_votre_cle_api" \
  "https://push.softafrik.com/api/v1/push/128/status" | jq .
5. Créer une campagne planifiée
curl -s -X POST \
  -H "X-API-Key: sk_live_votre_cle_api" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Campagne Ramadan 2026",
    "title": "Promo Ramadan",
    "message": "Des offres exceptionnelles",
    "platform": "android",
    "country": "CI",
    "scheduled_at": "2026-03-01 20:00:00"
  }' \
  "https://push.softafrik.com/api/v1/campaigns" | jq .
6. Révoquer un device
curl -s -X DELETE \
  -H "X-API-Key: sk_live_votre_cle_api" \
  "https://push.softafrik.com/api/v1/devices/123" | jq .

Exemple d'intégration PHP

<?php
class SoftAfrikPushClient {
    private string $apiKey;
    private string $baseUrl = 'https://push.softafrik.com/api/v1';

    public function __construct(string $apiKey) {
        $this->apiKey = $apiKey;
    }

    private function request(string $method, string $endpoint, array $data = null): array {
        $ch = curl_init($this->baseUrl . $endpoint);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'X-API-Key: ' . $this->apiKey
        ]);
        if ($data) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }
        if ($method === 'POST') curl_setopt($ch, CURLOPT_POST, true);
        if ($method === 'PUT') curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
        if ($method === 'DELETE') curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
        $response = curl_exec($ch);
        curl_close($ch);
        return json_decode($response, true) ?? [];
    }

    public function registerDevice(array $device): array {
        return $this->request('POST', '/devices', $device);
    }

    public function sendPush(array $push): array {
        return $this->request('POST', '/push/send', $push);
    }

    public function getQuota(): array {
        return $this->request('GET', '/quota');
    }
}

// Utilisation
$client = new SoftAfrikPushClient('sk_live_votre_cle_api');
$client->registerDevice([
    'push_token' => 'token_ici',
    'platform' => 'web',
    'external_user_id' => 'user_123'
]);
$client->sendPush([
    'title' => 'Bienvenue !',
    'message' => 'Merci de nous avoir rejoint.',
    'target_type' => 'all'
]);
?>

Service Worker (Web Push)

Exemple de firebase-messaging-sw.js pour recevoir les notifications Web Push :

importScripts('https://www.gstatic.com/firebasejs/10.0.0/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/10.0.0/firebase-messaging-compat.js');

firebase.initializeApp({
  apiKey: "YOUR_FIREBASE_API_KEY",
  projectId: "your-project-id",
  messagingSenderId: "123456789"
});

const messaging = firebase.messaging();

messaging.onBackgroundMessage(function(payload) {
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
    icon: '/icon.png',
    data: payload.data
  };
  self.registration.showNotification(notificationTitle, notificationOptions);
});

self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  const data = event.notification.data;
  if (data && data.tracking_url_click) {
    fetch(data.tracking_url_click);
  }
  event.waitUntil(clients.openWindow(data.action_url || '/'));
});
Besoin d'aide ? Contactez-nous à dak@softafrik.com ou consultez la FAQ.