Einführung
KD Push ist ein vollständig verwalteter Push-Dienst für Plattformen und ihre Händler. Händler berühren nie OneSignal, Firebase oder Apple-Zertifikate: Sie fügen ihre App im Portal hinzu, nehmen einen App Key und einen Server Key, und ihre Plattform sendet über diese API.
Alle Anfragen und Antworten sind JSON über HTTPS, Datumsangaben sind ISO 8601 und öffentliche IDs sind ULIDs.
Schnellstart
- 1App anlegen und Schlüssel holen
- 2Gerät aus der App registrierencURL
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" }' - 3Von Ihrem Server sendencURL
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" } }'
Authentifizierung
Jede App hat zwei Arten von Schlüsseln, jede mit genau einem Platz:
kdp_app_…X-KD-App-Key: kdp_app_…- Wo:
- In der mobilen App (öffentlich)
- Kann:
- Geräte registrieren, Konfiguration lesen, Öffnungen melden
- Kann niemals senden
kdp_live_…Authorization: Bearer kdp_live_…- Wo:
- Nur auf dem Server Ihrer Plattform (geheim)
- Kann:
- Senden, verfolgen, stornieren, Statistiken
- Wird einmal angezeigt – wir speichern nur einen Hash
404.Fehler
Jeder Fehler hat dieselbe Form und verrät nie Interna:
{
"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 warten.server_errorRatenlimits
Über dem Limit erhalten Sie 429 rate_limited mit einem Retry-After-Header. Das Senden an viele Geräte ist eine einzige Anfrage – die Engine verteilt sie intern.
Idempotenz
Senden Sie bei jedem Versand einen Idempotency-Key-Header mit (z. B. Ihre Ereignis-ID). Eine Wiederholung mit demselben Schlüssel innerhalb von 24 h liefert dieselbe Benachrichtigung mit 200, statt eine neue anzulegen – ein erneuter Versuch nach einem Netzwerkfehler ist also immer sicher.
Idempotency-Key: app-created-1234-v2.1.0Konfiguration
/sdk/configApp Key – Mobile AppBeim App-Start abrufen. Android liest hier seine Firebase-Optionen, sodass ein Wechsel des Firebase-Projekts oder Anbieters nie einen Neubau der App erfordert.
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
}
}
}Gerät registrieren
/sdk/devicesApp Key – Mobile AppBei jedem App-Start, Token-Wechsel, Login und Logout aufrufen. Beim ersten Mal 201, danach 200.
platformios | android | weberforderlichtokenstringerforderlichinstallation_iduuidoptionalproviderapns | fcm | webpushoptionalios.bundle_idstringoptionalBundle.main.bundleIdentifier.ios.profile_app_idstringoptionalapplication-identifier aus embedded.mobileprovision, ohne Team-Präfix.ios.team_idstring(10)optionalTeamIdentifier aus derselben Datei.ios.environmentproduction | sandboxoptionalaps-environment.android.fcm_project_idstringoptionalweb.p256dh · web.authbase64urlje nach Fallexternal_user_idstring | nulloptionalnull senden.user_signaturehexje nach Fallexternal_user_id erforderlich, solange die Identitätsprüfung aktiv ist. So wird sie berechnettagsobjectoptionallocale · timezone · app_version · os_version · device_model · sdk_versionstringoptionalcurl -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."
}
}Abmelden
/sdk/devices/unsubscribeApp Key – Mobile AppWenn der Nutzer Benachrichtigungen in der App ausschaltet. Das Gerät empfängt nichts mehr, bis es sich erneut registriert.
installation_iduuiderforderlichcurl -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
}Öffnen einer Benachrichtigung melden
/sdk/eventsApp Key – Mobile AppWenn der Nutzer auf eine Benachrichtigung tippt. Einmal pro Gerät und Nachricht gezählt, im Zähler „geöffnet“ angezeigt.
type"opened"erforderlichmessage_idULIDerforderlichkd_message_id aus dem Payload.installation_iduuiderforderlichcurl -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
}Website-Benachrichtigungen (Browser)
Dieselben Benachrichtigungen erreichen die Besucher Ihrer Website im Browser – ohne App, ohne Firebase, ohne Zertifikate: Jede App hat ihren eigenen VAPID-Schlüssel, erstellt von KD Push. Funktioniert in Chrome, Edge, Firefox, Samsung Internet und Safari auf dem Mac sowie auf iPhone und iPad, sobald die Website zum Home-Bildschirm hinzugefügt wurde (iOS 16.4+).
- Im Händlerportal: Ihre App →
Web, Website-Benachrichtigungen einschalten und Ihre Domain hinzufügen (oder von Ihrem Server mit PUT /app/web). - Legen Sie
/kdpush-sw.jsim Stammverzeichnis Ihrer Website mit dieser einen Zeile an:
importScripts('https://push.kd-app.com/sdk/web/v1/kdpush-sw.js');- Fügen Sie das SDK-Skript in jede Seite ein, vor
</head>:
<script src="https://push.kd-app.com/sdk/web/v1/kdpush.js"
data-app-key="kdp_app_…" async></script>Das war’s: Eine kleine Karte bittet Besucher, Benachrichtigungen einzuschalten (Text und Verzögerung legen Sie im Portal fest), der Browser wird automatisch registriert und meldet sich einmal am Tag. Ein Klick auf eine Benachrichtigung öffnet ihren Link und zählt als geöffnet.
Optionen und 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 von selbst (ios · android · desktop), sodass Sie z. B. eine iPhone-App nur Besuchern auf iPhones ankündigen können: {"platforms":["web"],"audience":{"type":"tags","tags":{"os":"ios"}}}. Hat Ihre Website schon einen eigenen Service Worker, fügen Sie ihm die importScripts-Zeile hinzu und richten Sie data-service-worker auf ihn.Web-Einstellungen
/app/webServer Key – Ihr ServerFür eine Plattform, die die Websites ihrer Händler verbindet: Web einschalten und die Domains setzen, wenn sich ein Shop verbindet oder die Domain wechselt. Das Einschalten braucht mindestens eine Domain und erstellt den VAPID-Schlüssel der App. Weggelassene Felder behalten ihren Wert.
enabledbooleanerforderlichoriginsstring[] ≤ 20je nach Fallicon_urlhttps URLoptionaldefault_urlURLoptionalprompt{enabled, delay_seconds, title, text}optionalcurl -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
}
}
}Benachrichtigung senden
/messagesServer Key – Ihr ServerSendet (oder plant) eine Benachrichtigung nur an die Geräte Ihrer App. Die Antwort kommt sofort mit dem Status queued; die Zustellung läuft im Hintergrund – Status und Zähler verfolgen Sie mit „Benachrichtigung abrufen“.
bodystring ≤ 2000erforderlichtitlestring ≤ 255optionalurlstringoptionalhttps://-Link oder ein In-App-Link wie neonstore://app/1234.image_urlhttps URLoptionaldataobject ≤ 30optionalkd_ beginnen, sind reserviert.audienceobjectoptional{"type":"all"} (Standard) · users + external_user_ids · devices + installation_ids · tags + tags – bis zu 1000 IDs.platforms["ios","android","web"]optionalscheduled_atISO 8601optionalttl_secondsintoptionalpriorityhigh | normaloptionalcollapse_idstring ≤ 64optionalHeader
Idempotency-Keystring ≤ 128optional402 subscription_inactive. Ohne Abonnement funktioniert nichts: keine Konfiguration (/sdk/config), keine Geräteregistrierung und keine Änderung der App-Einstellungen von Ihrem Server.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."
}
}Benachrichtigung abrufen
/messages/{id}Server Key – Ihr ServerStatus und Zähler. Jedes Feld erklärt das Nachrichtenobjekt.
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"
}
}Benachrichtigungen auflisten
/messagesServer Key – Ihr ServerDer Verlauf Ihrer App, neueste zuerst.
statusstringoptionalscheduled · queued · sending · sent · failed · canceledper_page1–100optionalcurl "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
}
}Benachrichtigung stornieren
/messages/{id}/cancelServer Key – Ihr ServerStorniert eine geplante, wartende oder gerade laufende Benachrichtigung. Noch nicht gesendete Pakete stoppen sofort.
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."
}
}App und Abonnement
/appServer Key – Ihr ServerPrüfen Sie den Schlüssel und ob Senden möglich ist, bevor Sie automatische Benachrichtigungen einschalten: sending.can_send berücksichtigt das Abonnement und das Kontingent dieses Monats, sending.reason nennt den Grund mit denselben Codes wie POST /messages (subscription_inactive · quota_exceeded). plan und usage zeigen den Stand des Händlers; portal verlinkt dorthin, wo er ihn behebt.
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
}
}
}Android-Paket
/app/androidServer Key – Ihr ServerFür eine Plattform, bei der der Händler das Android-Paket wählt: Senden Sie das Paket, mit dem die App des Shops gebaut wird, sobald es sich ändert – dann zeigt das Portal es an und eine später hochgeladene Firebase-Datei wird damit geprüft.
packagestringerforderlichcom.store.app.409 package_mismatch abgelehnt und firebase_package nennt das registrierte Paket – damit Android-Benachrichtigungen nie unbemerkt ausfallen.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"
}
}Gerätestatistik
/devices/statsServer Key – Ihr ServerAktive Geräte pro Plattform.
curl https://push.kd-app.com/api/v1/devices/stats \
-H "Authorization: Bearer kdp_live_…"{
"devices": {
"active": 1240,
"ios": 800,
"android": 440,
"web": 0
}
}Mit KD Push verbinden
Verbinden Sie den Shop eines Händlers mit einem Klick mit einer KD-Push-App, ohne dass jemand einen Schlüssel kopiert: Der Händler stimmt auf einer KD-Push-Seite zu und Ihre Plattform erhält die Schlüssel von Server zu Server (OAuth 2 Authorization Code mit PKCE).
- Wir registrieren Ihre Plattform und geben Ihnen
client_idundclient_secret, mit den exakt erlaubten Redirect-URIs. - Schicken Sie den Händler mit den Parametern unten zu
/portal/connect/authorize. - Der Händler meldet sich an oder erstellt ein Konto (vorausgefüllt mit Ihren Angaben), wählt oder erstellt die App und stimmt zu.
- Wir leiten ihn zurück zu
redirect_uri?code=…&state=…– odererror=access_denied, wenn er ablehnt. - Ihr Server tauscht den Code mit POST /connect/token gegen die Schlüssel.
Autorisierungsparameter
response_typecodeerforderlichclient_idstringerforderlichredirect_urihttps URLerforderlichstatestring ≤ 255erforderlichcode_challengebase64urlerforderlichBASE64URL(SHA256(code_verifier)); den code_verifier (43–128 Zeichen) bei sich behalten.code_challenge_methodS256erforderlichapp_namestring ≤ 120optionalios_bundle_idstringoptionalandroid_packagestringoptionalexternal_refstring ≤ 191optionalexternal_labelstring ≤ 255optionalhint_name · hint_email · hint_company · hint_phonestringoptionalstate. Der Code gilt 10 Minuten und nur einmal; wird er zweimal vorgelegt, wird widerrufen, was er erzeugt hat. Weder code_verifier noch client_secret erreichen je den Browser.// 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));Code einlösen
/connect/tokenclient_id + client_secretgrant_typeauthorization_codeerforderlichclient_id · client_secretstringerforderlichcodestringerforderlichredirect_uristringerforderlichcode_verifierstringerforderlichSie erhalten den app_key (für die App), einen für diese Verbindung neu ausgestellten server_key (wird einmal angezeigt), das identity_secret und den Stand des Händlers in account – im selben Format wie 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."
}
}Trennen
/connect/revokeServer Key – Ihr ServerDer gesendete Server Key funktioniert sofort nicht mehr; App, Geräte und Verlauf bleiben beim Händler. Der Händler kann auch in seinem Panel trennen – Ihr Schlüssel antwortet dann mit 401 invalid_server_key; behandeln Sie das als getrennt.
curl -X POST https://push.kd-app.com/api/v1/connect/revoke \
-H "Authorization: Bearer kdp_live_…"{
"revoked": true
}Das Nachrichtenobjekt
idULIDoptionalstatusstringoptionalsent, sobald mindestens ein Gerät sie angenommen hat, failed, wenn keines (Grund in error).sourceapi | portal | adminoptionalcounts.targetedintoptionalcounts.sentintoptionalcounts.invalidintoptionalcounts.failedintoptionalcounts.openedintoptionalfailures[{provider, code, http_status, count}]optionalTopicDisallowed), der HTTP-Status und die Anzahl der Geräte.created_at · started_at · finished_at · scheduled_atISO 8601optionalPrüfung der Nutzeridentität
Um ein Gerät mit einem Nutzer zu verknüpfen (für persönliche Benachrichtigungen wie „Ihr Abo endet bald“), braucht die App eine Signatur, die Ihr Server nach dem Login berechnet – sonst könnte jeder sein Telefon als anderer Nutzer registrieren und dessen Benachrichtigungen erhalten.
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];Was die App empfängt
{
"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"
}
}Beim Antippen kd_url öffnen und kd_message_id an /sdk/events senden. Werte in data kommen als Text an.
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
});Integrations-Checkliste für Plattformen
- 1Der Händler legt die App im Portal an und fügt App Key und Server Key in das Panel Ihrer Plattform ein.
- 2Ihre Plattform baut die App mit dem App Key – die App ruft /sdk/config auf und registriert dann das Gerät.
- 3Nach dem Login gibt Ihr Server der App eine user_signature für die Nutzer-ID.
- 4Ihre Plattform sendet automatische Benachrichtigungen (neue App, Update) mit einem Idempotency-Key pro Ereignis.
- 5Wird ein Katalog zum ersten Mal verbunden, nicht pro App benachrichtigen – eine Zusammenfassung senden.
- 6Vor dem Einschalten automatischer Benachrichtigungen subscription.can_send über /app prüfen.
Postman
- Sammlung herunterladen und in Postman importieren (Import → Datei wählen).
- In den Variablen der Sammlung
app_key,server_keyund einen Test-Geräte-Token indevice_tokensetzen. - Führen Sie Register device und dann Send a notification aus – die ID wird für die folgenden Anfragen in
message_idgespeichert. - Optional:
external_user_idundidentity_secretsetzen, dann berechnet die Sammlunguser_signatureselbst.