Introduction
KD Push est un service push entièrement géré pour les plateformes et leurs marchands. Les marchands ne touchent jamais à OneSignal, à Firebase ni aux certificats Apple : ils ajoutent leur application dans le portail, récupèrent une App Key et une Server Key, et leur plateforme envoie via cette API.
Toutes les requêtes et réponses sont en JSON sur HTTPS, les dates en ISO 8601 et les identifiants publics sont des ULID.
Démarrage rapide
- 1Créez votre application et récupérez ses clésDans le portail marchand : Nouvelle application → copiez l’
App Keyet laServer Key(affichée une seule fois). - 2Enregistrez l’appareil depuis l’applicationcURL
curl -X POST https://push.kd-app.com/api/v1/sdk/devices \ -H "X-KD-App-Key: kdp_app_…" \ -H "Content-Type: application/json" \ -d '{ "platform": "android", "token": "fcm-registration-token", "installation_id": "3f0c9a2e-6b1d-4c8e-9f7a-2d5e8b1c4a90", "android": { "fcm_project_id": "neon-push" }, "external_user_id": "42", "user_signature": "9f2c4e…", "locale": "ar", "app_version": "2.1.0" }' - 3Envoyez depuis votre serveurcURL
curl -X POST https://push.kd-app.com/api/v1/messages \ -H "Authorization: Bearer kdp_live_…" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: app-created-1234" \ -d '{ "title": "تطبيق جديد", "body": "تمت إضافة واتساب الذهبي للمتجر", "url": "neonstore://app/1234", "image_url": "https://cdn.example.com/icons/1234.png", "data": { "app_id": "1234" }, "audience": { "type": "all" } }'
Authentification
Chaque application a deux types de clés, chacune à une seule place :
kdp_app_…X-KD-App-Key: kdp_app_…- Où :
- Dans l’application mobile (publique)
- Peut :
- Enregistrer les appareils, lire la configuration, signaler les ouvertures
- Ne peut jamais envoyer
kdp_live_…Authorization: Bearer kdp_live_…- Où :
- Uniquement sur le serveur de votre plateforme (secrète)
- Peut :
- Envoyer, suivre, annuler, statistiques
- Affichée une seule fois — nous ne stockons qu’un hash
404.Erreurs
Toutes les erreurs ont la même forme et ne révèlent jamais de détails internes :
{
"error": {
"code": "validation_failed",
"message": "The body field is required.",
"fields": {
"body": [
"The body field is required."
]
}
}
}invalid_app_keyinvalid_server_keysubscription_inactivequota_exceededinvalid_user_signatureweb_disabled · origin_not_allowedinvalid_subscription · provider_mismatchapp_disabled · account_bannednot_foundnot_cancelablevalidation_failedfields.invalid_tokenrate_limitedRetry-After.server_errorLimites de débit
Au-delà de la limite, vous recevez 429 rate_limited avec un en-tête Retry-After. Envoyer à de nombreux appareils reste une seule requête — le moteur la répartit en interne.
Idempotence
Envoyez un en-tête Idempotency-Key avec chaque envoi (p. ex. l’id de votre événement). Répéter la requête avec la même clé dans les 24 h renvoie la même notification avec 200 au lieu d’en créer une nouvelle — réessayer après une coupure réseau est donc toujours sûr.
Idempotency-Key: app-created-1234-v2.1.0Configuration
/sdk/configApp Key — application mobileRécupérez-la au démarrage de l’application. Android y lit ses options Firebase : changer de projet Firebase ou de fournisseur n’exige donc jamais de recompiler l’application.
Cache-Control: max-age=300.curl https://push.kd-app.com/api/v1/sdk/config \
-H "X-KD-App-Key: kdp_app_…"{
"app": {
"id": "01JB2Q6V8K4Y3N5M7R9T1W0XZC",
"name": "My Store"
},
"identity_verification": "required",
"android": {
"provider": "fcm",
"firebase": {
"project_id": "neon-push",
"app_id": "1:123456789:android:abcdef",
"api_key": "AIza…",
"sender_id": "123456789",
"storage_bucket": null
}
},
"ios": {
"provider": "apns"
},
"web": {
"provider": "webpush",
"vapid_public_key": "BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U",
"icon_url": null,
"prompt": {
"enabled": true,
"delay_seconds": 6,
"title": null,
"text": null
}
}
}Enregistrer un appareil
/sdk/devicesApp Key — application mobileAppelez-le à chaque démarrage de l’application, renouvellement du jeton, connexion et déconnexion. 201 la première fois, 200 ensuite.
platformios | android | webobligatoiretokenstringobligatoireinstallation_iduuidfacultatifproviderapns | fcm | webpushfacultatifios.bundle_idstringfacultatifBundle.main.bundleIdentifier.ios.profile_app_idstringfacultatifapplication-identifier issu de embedded.mobileprovision, sans le préfixe d’équipe.ios.team_idstring(10)facultatifTeamIdentifier du même fichier.ios.environmentproduction | sandboxfacultatifaps-environment.android.fcm_project_idstringfacultatifweb.p256dh · web.authbase64urlselon le casexternal_user_idstring | nullfacultatifnull à la déconnexion.user_signaturehexselon le casexternal_user_id tant que la vérification d’identité est active. Comment la calculertagsobjectfacultatiflocale · timezone · app_version · os_version · device_model · sdk_versionstringfacultatifcurl -X POST https://push.kd-app.com/api/v1/sdk/devices \
-H "X-KD-App-Key: kdp_app_…" \
-H "Content-Type: application/json" \
-d '{
"platform": "android",
"token": "fcm-registration-token",
"installation_id": "3f0c9a2e-6b1d-4c8e-9f7a-2d5e8b1c4a90",
"android": { "fcm_project_id": "neon-push" },
"external_user_id": "42",
"user_signature": "9f2c4e…",
"locale": "ar",
"app_version": "2.1.0"
}'{
"device": {
"installation_id": "3f0c9a2e-6b1d-4c8e-9f7a-2d5e8b1c4a90",
"platform": "android",
"status": "active",
"external_user_id": "42"
}
}{
"error": {
"code": "invalid_user_signature",
"message": "user_signature does not match external_user_id."
}
}Désabonnement
/sdk/devices/unsubscribeApp Key — application mobileQuand l’utilisateur désactive les notifications dans l’application. L’appareil ne reçoit plus rien jusqu’à ce qu’il s’enregistre à nouveau.
installation_iduuidobligatoirecurl -X POST https://push.kd-app.com/api/v1/sdk/devices/unsubscribe \
-H "X-KD-App-Key: kdp_app_…" \
-H "Content-Type: application/json" \
-d '{ "installation_id": "3f0c9a2e-6b1d-4c8e-9f7a-2d5e8b1c4a90" }'{
"unsubscribed": true
}Signaler l’ouverture d’une notification
/sdk/eventsApp Key — application mobileQuand l’utilisateur touche une notification. Comptée une fois par appareil et par message, affichée dans le compteur « ouvertes ».
type"opened"obligatoiremessage_idULIDobligatoirekd_message_id du payload.installation_iduuidobligatoirecurl -X POST https://push.kd-app.com/api/v1/sdk/events \
-H "X-KD-App-Key: kdp_app_…" \
-H "Content-Type: application/json" \
-d '{
"type": "opened",
"message_id": "01JB2QA4N7C2X9V5B8M3K6P1RD",
"installation_id": "3f0c9a2e-6b1d-4c8e-9f7a-2d5e8b1c4a90"
}'{
"accepted": true
}Notifications du site (navigateurs)
Les mêmes notifications atteignent les visiteurs de votre site dans leur navigateur — sans application, sans Firebase, sans certificats : chaque application a sa propre clé VAPID, créée par KD Push. Fonctionne dans Chrome, Edge, Firefox, Samsung Internet et Safari sur Mac, et sur iPhone et iPad une fois le site ajouté à l’écran d’accueil (iOS 16.4+).
- Dans le portail marchand : votre application →
Web, activez les notifications du site et ajoutez votre domaine (ou depuis votre serveur avec PUT /app/web). - Créez
/kdpush-sw.jsà la racine de votre site avec cette seule ligne :
importScripts('https://push.kd-app.com/sdk/web/v1/kdpush-sw.js');- Ajoutez le script du SDK à chaque page, avant
</head>:
<script src="https://push.kd-app.com/sdk/web/v1/kdpush.js"
data-app-key="kdp_app_…" async></script>C’est tout : une petite carte invite les visiteurs à activer les notifications (son texte et son délai se règlent dans le portail), le navigateur est enregistré automatiquement et se manifeste une fois par jour. Un clic sur une notification ouvre son lien et compte comme une ouverture.
Options et API
<!-- data-* options -->
data-app-key required
data-service-worker /kdpush-sw.js (default)
data-prompt "off" hides the built-in card
data-lang ar | en | es | fr | de (default: the page language)
data-user-id your user id + data-user-signature (identity verification)
data-tags JSON, e.g. '{"plan":"vip"}'
// JavaScript
KDPush.subscribe() // ask (from a click) and subscribe → "subscribed" | "denied" | "default" | "unsupported" | "disabled"
KDPush.unsubscribe()
KDPush.isSubscribed() // Promise<boolean>
KDPush.login('42', signature) // link the browser to your user
KDPush.logout()
KDPush.setTags({ plan: 'vip' })os (ios · android · desktop) : vous pouvez par exemple annoncer une application iPhone uniquement aux visiteurs sur iPhone : {"platforms":["web"],"audience":{"type":"tags","tags":{"os":"ios"}}}. Si votre site a déjà son propre service worker, ajoutez-y la ligne importScripts et faites pointer data-service-worker vers lui.Paramètres web
/app/webServer Key — votre serveurPour une plateforme qui relie les sites de ses marchands : activez le web et définissez les domaines quand une boutique se connecte ou change de domaine. L’activation exige au moins un domaine et crée la clé VAPID de l’application. Les champs omis gardent leur valeur.
enabledbooleanobligatoireoriginsstring[] ≤ 20selon le casicon_urlhttps URLfacultatifdefault_urlURLfacultatifprompt{enabled, delay_seconds, title, text}facultatifcurl -X PUT https://push.kd-app.com/api/v1/app/web \
-H "Authorization: Bearer kdp_live_…" \
-H "Content-Type: application/json" \
-d '{"enabled":true,"origins":["shop.example.com"],"icon_url":"https://cdn.example.com/logo.png"}'{
"web": {
"enabled": true,
"origins": [
"https://shop.example.com",
"https://www.shop.example.com"
],
"vapid_public_key": "BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U",
"subscribers": 0,
"icon_url": "https://cdn.example.com/logo.png",
"default_url": null,
"prompt": {
"enabled": true,
"delay_seconds": 6,
"title": null,
"text": null
}
}
}Envoyer une notification
/messagesServer Key — votre serveurEnvoie (ou planifie) une notification aux seuls appareils de votre application. La réponse est immédiate avec le statut queued ; la livraison se fait en arrière-plan — suivez le statut et les compteurs avec Consulter une notification.
bodystring ≤ 2000obligatoiretitlestring ≤ 255facultatifurlstringfacultatifhttps:// ou un lien interne comme neonstore://app/1234.image_urlhttps URLfacultatifdataobject ≤ 30facultatifkd_ sont réservées.audienceobjectfacultatif{"type":"all"} (par défaut) · users + external_user_ids · devices + installation_ids · tags + tags — jusqu’à 1000 ids.platforms["ios","android","web"]facultatifscheduled_atISO 8601facultatifttl_secondsintfacultatifpriorityhigh | normalfacultatifcollapse_idstring ≤ 64facultatifEn-têtes
Idempotency-Keystring ≤ 128facultatif402 subscription_inactive. Sans abonnement, rien ne fonctionne : ni configuration (/sdk/config), ni enregistrement d’appareils, ni modification des réglages de l’application depuis votre serveur.curl -X POST https://push.kd-app.com/api/v1/messages \
-H "Authorization: Bearer kdp_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: app-created-1234" \
-d '{
"title": "تطبيق جديد",
"body": "تمت إضافة واتساب الذهبي للمتجر",
"url": "neonstore://app/1234",
"image_url": "https://cdn.example.com/icons/1234.png",
"data": { "app_id": "1234" },
"audience": { "type": "all" }
}'{
"message": {
"id": "01JB2QA4N7C2X9V5B8M3K6P1RD",
"status": "queued",
"source": "api",
"title": "تطبيق جديد",
"body": "تمت إضافة واتساب الذهبي للمتجر",
"image_url": "https://cdn.example.com/icons/1234.png",
"url": "neonstore://app/1234",
"data": {
"app_id": "1234"
},
"audience": {
"type": "all"
},
"platforms": null,
"scheduled_at": null,
"counts": {
"targeted": 0,
"sent": 0,
"failed": 0,
"invalid": 0,
"opened": 0
},
"error": null,
"failures": [],
"created_at": "2026-10-03T12:00:00+00:00",
"started_at": null,
"finished_at": null
}
}{
"error": {
"code": "subscription_inactive",
"message": "No active KD Push subscription for this account."
}
}Consulter une notification
/messages/{id}Server Key — votre serveurStatut et compteurs. Voir l’objet message pour chaque champ.
curl https://push.kd-app.com/api/v1/messages/01JB2QA4N7C2X9V5B8M3K6P1RD \
-H "Authorization: Bearer kdp_live_…"{
"message": {
"id": "01JB2QA4N7C2X9V5B8M3K6P1RD",
"status": "sent",
"source": "api",
"title": "تطبيق جديد",
"body": "تمت إضافة واتساب الذهبي للمتجر",
"image_url": "https://cdn.example.com/icons/1234.png",
"url": "neonstore://app/1234",
"data": {
"app_id": "1234"
},
"audience": {
"type": "all"
},
"platforms": null,
"scheduled_at": null,
"counts": {
"targeted": 1240,
"sent": 1227,
"failed": 3,
"invalid": 10,
"opened": 214
},
"error": null,
"failures": [],
"created_at": "2026-10-03T12:00:00+00:00",
"started_at": "2026-10-03T12:00:01+00:00",
"finished_at": "2026-10-03T12:00:04+00:00"
}
}Lister les notifications
/messagesServer Key — votre serveurL’historique de votre application, du plus récent au plus ancien.
statusstringfacultatifscheduled · queued · sending · sent · failed · canceledper_page1–100facultatifcurl "https://push.kd-app.com/api/v1/messages?status=sent&per_page=20" \
-H "Authorization: Bearer kdp_live_…"{
"data": [
{
"id": "01JB2QA4N7C2X9V5B8M3K6P1RD",
"status": "sent",
"source": "api",
"title": "تطبيق جديد",
"body": "تمت إضافة واتساب الذهبي للمتجر",
"image_url": "https://cdn.example.com/icons/1234.png",
"url": "neonstore://app/1234",
"data": {
"app_id": "1234"
},
"audience": {
"type": "all"
},
"platforms": null,
"scheduled_at": null,
"counts": {
"targeted": 0,
"sent": 0,
"failed": 0,
"invalid": 0,
"opened": 0
},
"error": null,
"failures": [],
"created_at": "2026-10-03T12:00:00+00:00",
"started_at": null,
"finished_at": null
}
],
"meta": {
"current_page": 1,
"per_page": 20,
"total": 1,
"last_page": 1
}
}Annuler une notification
/messages/{id}/cancelServer Key — votre serveurAnnule une notification planifiée, en file d’attente ou en cours d’envoi. Les lots pas encore envoyés s’arrêtent immédiatement.
curl -X POST https://push.kd-app.com/api/v1/messages/01JB2QA4N7C2X9V5B8M3K6P1RD/cancel \
-H "Authorization: Bearer kdp_live_…"{
"message": {
"id": "01JB2QA4N7C2X9V5B8M3K6P1RD",
"status": "canceled",
"source": "api",
"title": "تطبيق جديد",
"body": "تمت إضافة واتساب الذهبي للمتجر",
"image_url": "https://cdn.example.com/icons/1234.png",
"url": "neonstore://app/1234",
"data": {
"app_id": "1234"
},
"audience": {
"type": "all"
},
"platforms": null,
"scheduled_at": null,
"counts": {
"targeted": 0,
"sent": 0,
"failed": 0,
"invalid": 0,
"opened": 0
},
"error": null,
"failures": [],
"created_at": "2026-10-03T12:00:00+00:00",
"started_at": null,
"finished_at": null
}
}{
"error": {
"code": "not_cancelable",
"message": "Only scheduled, queued or sending messages can be canceled."
}
}Application et abonnement
/appServer Key — votre serveurVérifiez la clé et la possibilité d’envoyer avant d’activer les notifications automatiques : sending.can_send tient compte de l’abonnement et du quota du mois, et sending.reason donne la cause avec les codes de POST /messages (subscription_inactive · quota_exceeded). plan et usage montrent la situation du marchand ; portal renvoie là où il peut la corriger.
curl https://push.kd-app.com/api/v1/app \
-H "Authorization: Bearer kdp_live_…"{
"app": {
"id": "01JB2Q6V8K4Y3N5M7R9T1W0XZC",
"name": "My Store",
"platform": "neon",
"status": "active",
"ios_bundle_id": "com.store.app",
"android_package": "com.store.app"
},
"subscription": {
"status": "active",
"expires_at": "2026-11-02T12:00:00+00:00",
"grace_until": null,
"days_left": 19,
"can_send": true
},
"plan": {
"name": "Pro",
"period": "monthly",
"monthly_messages": 100000,
"max_devices": null,
"max_apps": 3
},
"usage": {
"deliveries_this_month": 18240,
"remaining_this_month": 81760,
"active_devices": 1240
},
"sending": {
"can_send": true,
"reason": null
},
"portal": {
"plans": "https://push.kd-app.com/portal/plans",
"subscription": "https://push.kd-app.com/portal/subscription"
},
"devices": {
"active": 1240,
"ios": 800,
"android": 440,
"web": 0
},
"web": {
"enabled": false,
"origins": [],
"vapid_public_key": null,
"subscribers": 0,
"icon_url": null,
"default_url": null,
"prompt": {
"enabled": true,
"delay_seconds": 6,
"title": null,
"text": null
}
}
}Package Android
/app/androidServer Key — votre serveurPour une plateforme qui laisse son marchand choisir le package Android : envoyez le package avec lequel l’application de la boutique est compilée à chaque changement, pour que le portail l’affiche et que le fichier Firebase envoyé plus tard soit vérifié avec lui.
packagestringobligatoirecom.store.app.409 package_mismatch et firebase_package indique celui qui est enregistré — pour que les notifications Android ne s’arrêtent jamais en silence.curl -X PUT https://push.kd-app.com/api/v1/app/android \
-H "Authorization: Bearer kdp_live_…" \
-H "Content-Type: application/json" \
-d '{"package":"com.store.app"}'{
"app": {
"id": "01JB2Q6V8K4Y3N5M7R9T1W0XZC",
"android_package": "com.store.app"
}
}{
"error": {
"code": "package_mismatch",
"message": "The app's Firebase project is registered for com.store.app; upload one for com.other.app first.",
"firebase_package": "com.store.app"
}
}Statistiques des appareils
/devices/statsServer Key — votre serveurAppareils actifs par plateforme.
curl https://push.kd-app.com/api/v1/devices/stats \
-H "Authorization: Bearer kdp_live_…"{
"devices": {
"active": 1240,
"ios": 800,
"android": 440,
"web": 0
}
}Se connecter avec KD Push
Reliez la boutique d’un marchand à une application KD Push en un clic, sans que personne ne copie de clé : le marchand approuve sur une page KD Push et votre plateforme reçoit les clés de serveur à serveur (OAuth 2 authorization code avec PKCE).
- Nous enregistrons votre plateforme et vous donnons un
client_idet unclient_secret, avec les URI de redirection exactes autorisées. - Envoyez le marchand vers
/portal/connect/authorizeavec les paramètres ci-dessous. - Le marchand se connecte ou crée un compte (prérempli avec vos données), choisit ou crée l’application, puis autorise.
- Nous le renvoyons vers
redirect_uri?code=…&state=…— ouerror=access_denieds’il refuse. - Votre serveur échange le code contre les clés avec POST /connect/token.
Paramètres d’autorisation
response_typecodeobligatoireclient_idstringobligatoireredirect_urihttps URLobligatoirestatestring ≤ 255obligatoirecode_challengebase64urlobligatoireBASE64URL(SHA256(code_verifier)) ; gardez le code_verifier (43–128 caractères) de votre côté.code_challenge_methodS256obligatoireapp_namestring ≤ 120facultatifios_bundle_idstringfacultatifandroid_packagestringfacultatifexternal_refstring ≤ 191facultatifexternal_labelstring ≤ 255facultatifhint_name · hint_email · hint_company · hint_phonestringfacultatifstate. Le code vit 10 minutes et ne sert qu’une fois ; le présenter deux fois révoque ce qu’il a produit. Ni le code_verifier ni le client_secret n’atteignent jamais le navigateur.// 1. Send the merchant to KD Push (keep $verifier and $state in their session)
$verifier = Str::random(64);
$state = Str::random(40);
session(['kdpush' => compact('verifier', 'state')]);
return redirect('https://push.kd-app.com/portal/connect/authorize?' . http_build_query([
'response_type' => 'code',
'client_id' => config('services.kdpush.connect_client_id'),
'redirect_uri' => 'https://your-platform.example/kdpush/callback',
'state' => $state,
'code_challenge' => rtrim(strtr(base64_encode(hash('sha256', $verifier, true)), '+/', '-_'), '='),
'code_challenge_method' => 'S256',
'app_name' => $store->name, // optional: prefills a new app
'ios_bundle_id' => $store->bundleId, // optional
'android_package' => $store->androidPackage, // optional
'external_ref' => $store->id, // optional: your id for the store
'hint_email' => $owner->email, // optional: prefills sign-up
], '', '&', PHP_QUERY_RFC3986));Échanger le code
/connect/tokenclient_id + client_secretgrant_typeauthorization_codeobligatoireclient_id · client_secretstringobligatoirecodestringobligatoireredirect_uristringobligatoirecode_verifierstringobligatoireVous recevez l’app_key (pour l’application), une nouvelle server_key émise pour cette connexion (affichée une seule fois), l’identity_secret et la situation du marchand dans account — au même format que GET /app.
curl -X POST https://push.kd-app.com/api/v1/connect/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"client_id": "kdp_cli_…",
"client_secret": "kdp_cs_…",
"code": "kdp_code_…",
"redirect_uri": "https://your-platform.example/kdpush/callback",
"code_verifier": "…"
}'{
"connection": {
"id": "01JB2QX5V8K4Y3N5M7R9T1W0XZ",
"connected_at": "2026-10-14T12:00:00+00:00"
},
"app": {
"id": "01JB2Q6V8K4Y3N5M7R9T1W0XZC",
"name": "My Store",
"platform": "neon",
"ios_bundle_id": "com.store.app",
"android_package": null
},
"merchant": {
"name": "Store owner",
"email": "[email protected]"
},
"app_key": "kdp_app_…",
"server_key": "kdp_live_…",
"identity_secret": "…",
"api_base": "https://push.kd-app.com/api/v1",
"account": {
"subscription": {
"status": "active",
"expires_at": "2026-11-02T12:00:00+00:00",
"grace_until": null,
"days_left": 19,
"can_send": true
},
"plan": {
"name": "Pro",
"period": "monthly",
"monthly_messages": 100000,
"max_devices": null,
"max_apps": 3
},
"usage": {
"deliveries_this_month": 18240,
"remaining_this_month": 81760,
"active_devices": 1240
},
"sending": {
"can_send": true,
"reason": null
},
"portal": {
"plans": "https://push.kd-app.com/portal/plans",
"subscription": "https://push.kd-app.com/portal/subscription"
}
}
}{
"error": {
"code": "invalid_grant",
"message": "Authorization code already used."
}
}Déconnecter
/connect/revokeServer Key — votre serveurLa Server Key envoyée cesse immédiatement de fonctionner ; l’application, ses appareils et son historique restent au marchand. Le marchand peut aussi se déconnecter depuis son panneau — votre clé répond alors 401 invalid_server_key ; traitez cela comme une déconnexion.
curl -X POST https://push.kd-app.com/api/v1/connect/revoke \
-H "Authorization: Bearer kdp_live_…"{
"revoked": true
}L’objet message
idULIDfacultatifstatusstringfacultatifsent dès qu’au moins un appareil l’a acceptée, failed si aucun ne l’a fait (raison dans error).sourceapi | portal | adminfacultatifcounts.targetedintfacultatifcounts.sentintfacultatifcounts.invalidintfacultatifcounts.failedintfacultatifcounts.openedintfacultatiffailures[{provider, code, http_status, count}]facultatifTopicDisallowed), le statut HTTP et le nombre d’appareils.created_at · started_at · finished_at · scheduled_atISO 8601facultatifVérification de l’identité de l’utilisateur
Pour lier un appareil à un utilisateur (pour des notifications personnelles comme « votre abonnement se termine bientôt »), l’application a besoin d’une signature calculée par votre serveur après la connexion — sinon n’importe qui pourrait enregistrer son téléphone au nom d’un autre utilisateur et recevoir ses notifications.
user_signature = hex( HMAC-SHA256( external_user_id , identity_secret ) )// After the user logs in — on your backend, never in the app
$signature = hash_hmac('sha256', (string) $user->id, config('services.kdpush.identity_secret'));
return ['user_id' => $user->id, 'push_signature' => $signature];Ce que reçoit l’application
{
"aps": {
"alert": {
"title": "تطبيق جديد",
"body": "تمت إضافة واتساب الذهبي للمتجر"
},
"sound": "default",
"mutable-content": 1
},
"kd_message_id": "01JB2QA4N7C2X9V5B8M3K6P1RD",
"kd_url": "neonstore://app/1234",
"kd_image": "https://cdn.example.com/icons/1234.png",
"app_id": "1234"
}{
"notification": {
"title": "تطبيق جديد",
"body": "تمت إضافة واتساب الذهبي للمتجر",
"image": "https://cdn.example.com/icons/1234.png"
},
"data": {
"kd_message_id": "01JB2QA4N7C2X9V5B8M3K6P1RD",
"kd_url": "neonstore://app/1234",
"app_id": "1234"
}
}Ouvrez kd_url au toucher et envoyez kd_message_id à /sdk/events. Les valeurs de data arrivent sous forme de texte.
FirebaseMessaging.onMessageOpenedApp.listen((message) {
final url = message.data['kd_url'];
final id = message.data['kd_message_id'];
if (url != null) openDeepLink(url); // e.g. neonstore://app/1234
if (id != null) reportOpened(id); // POST /sdk/events
});Liste de contrôle d’intégration de la plateforme
- 1Le marchand crée l’application dans le portail et colle l’App Key et la Server Key dans le panneau de votre plateforme.
- 2Votre plateforme compile l’application avec l’App Key intégrée — l’application appelle /sdk/config, puis enregistre l’appareil.
- 3Après la connexion, votre serveur remet à l’application une user_signature pour l’id de l’utilisateur.
- 4Votre plateforme envoie des notifications automatiques (nouvelle application, mise à jour) avec une Idempotency-Key par événement.
- 5Quand un catalogue est connecté pour la première fois, ne notifiez pas chaque application — envoyez un seul récapitulatif.
- 6Vérifiez subscription.can_send via /app avant d’activer les notifications automatiques.
Postman
- Téléchargez la collection et importez-la dans Postman (Import → choisissez le fichier).
- Dans les variables de la collection, renseignez
app_key,server_keyet un jeton d’appareil de test dansdevice_token. - Lancez Register device, puis Send a notification — l’id est enregistré dans
message_idpour les requêtes suivantes. - Facultatif : renseignez
external_user_idetidentity_secret, et la collection calculeuser_signatureelle-même.