API-Referenz
Alle /v1-Endpunkte aus der Backend-Spezifikation: Pfade, Parameter, Schemas, Enums und Fehler entsprechen dem Server.
Live
https://api.tongkhoesim.com/v1Testmodus
https://api-testing.tongkhoesim.com/v1Produktiv: api.tongkhoesim.com / tke_live_ (Partner) oder tke_member_live_ (freigeschaltete Mitglieder). Test: api-testing.tongkhoesim.com / tke_test_ / tke_member_test_ (Partner / Mitglieder).
Allgemeine Konventionen
Diese 6 Regeln gelten für alle 30 Operationen.
Alle Endpunkte einschließlich GET: HMAC-SHA256 mit 4 Headern: X-TKE-Key · X-TKE-Timestamp · X-TKE-Nonce · X-TKE-Signature. Kein Zugriff ohne Signatur.
Gleicher Schlüssel und Body innerhalb 24 h: Ergebnis ohne erneute Abbuchung wiedergegeben. Pro api_key_id. Pflicht bei 5 Operationen: POST /v1/orders, POST /v1/orders/bulk, POST /v1/esims/{id}/cancel, POST /v1/esims/{id}/change-plan, POST /v1/esims/{id}/refund-requests.
Seitennavigation: zwei Modelle
Formate und Abbruchbedingungen unterscheiden sich. Behandeln Sie beide Modelle getrennt.
Nur GET /v1/webhooks/deliveries. Liefert page, page_size und total.
Außerhalb des Bereichs: HTTP 200, items: [] und echtes total. Bei leerer Liste oder erreichtem total stoppen.
Für /v1/catalog/packages, /v1/orders, /v1/esims und /v1/esims/{id}/plan-options. updated_since ist nur bei orders und esims möglich.
Stoppen, wenn next_cursor fehlt oder dem aktuellen Cursor entspricht. Das Feld kann in data ganz fehlen.
Ungültige Cursor beginnen für ältere Clients ohne Fehler von vorn. Eine Prüfung nur auf next_cursor !== null kann die erste Seite endlos wiederholen.
let cursor = null;
const seen = new Set();
while (true) {
const params = new URLSearchParams({ page_size: "200" });
if (cursor) params.set("cursor", cursor);
// callSigned ergänzt Ihre 4 X-TKE-*-Header (HMAC-Seite).
const page = await callSigned("GET", `/v1/orders?${params}`);
for (const order of page.data.items) await handle(order);
const next = page.data.next_cursor;
if (!next || next === cursor || seen.has(next)) break;
seen.add(next);
cursor = next;
}Katalog
Paketkatalog mit EINER Oberfläche für beide Versorgungssysteme. Das System ist ein FELD (`market`: `domestic` | `international`) und Filter (`?market=`), nicht zwei getrennte Pfade. KEINE Bestandsangaben: keine Menge oder Stufe `available`/`low`/`out_of_stock`. Pakete erscheinen einfach; bei fehlender Lieferfähigkeit liefert `POST /v1/orders` einen klaren Fehler (`esim.out_of_stock`…), statt vorab im Katalog zu warnen. Einheitliche Cursor-Paginierung. `total` nur bei günstigem Zählen (Filter auf Inland), sonst `null`.
/v1/catalog/packagesPakete auflisten
catalog:readget_catalog_packagesErforderlicher Berechtigungsbereich: catalog:read.
Paketkatalog Ihrer Organisation: eine gemeinsame Oberfläche für beide Versorgungssysteme, gefiltert mit ?market=.
Es erscheinen nur tatsächlich KAUFBARE Pakete: veröffentlicht, weiterhin beim Anbieter vertrieben, durch den Schlüssel erlaubt UND für Ihre Organisation bepreist. Pakete ohne Preis fehlen, weil sie nicht bestellt werden können.
Cursor-Paginierung: zuerst ohne cursor aufrufen, dann next_cursor unverändert zurückgeben, bis es null ist. Eine kürzere Seite als page_size bedeutet NICHT das Ende.
capabilities stammt aus echten Paketangaben; fehlen diese, sind alle Flags false. Ein möglicher Button wird eher weggelassen, als ein sicher mit 422 scheiternder Endpunkt versprochen.
Der Katalog enthält KEINE Bestandsangaben, weder Mengen noch verfügbar/ausverkauft. Kann der Anbieter nicht liefern, meldet POST /v1/orders unmittelbar einen klaren Fehler (esim.out_of_stock…), statt eine Vorabinterpretation eines Feldes zu verlangen.
Query-Parameter (18)
page_sizeintegeroptionalStandard 50min 1max 100Datensätze pro Seite. Standard 50, höchstens 100. Höhere Werte werden ohne Fehler auf 100 begrenzt.
marketstringoptionalVersorgungssystem: domestic | international. Unbekannte Werte führen zu internal.invalid_filter (400), nicht zum vollständigen Katalog. Ein Tippfehler darf nicht als wirkungsloser Filter erscheinen.
countrystringoptionalLändercode nach ISO-3166 alpha-2 (z. B. VN). Nur Pakete mit Abdeckung dieses Landes.
regionstringoptionalRegionskennung (z. B. chau-a). Pakete mit mindestens einem Land dieser Region sowie alle globalen Pakete.
qstringoptionalFreitextsuche nach öffentlichem Code und Paketname (Teiltreffer, ohne Beachtung der Groß-/Kleinschreibung).
tagstringoptionalNach EINEM kommerziellen Tag filtern. Überflüssige Leerzeichen werden entfernt, Kleinbuchstaben und Bindestriche verwendet: Ban Le und ban-le sind derselbe Tag.
data_modelstringoptionalDatenmodell: daily | fixed | unlimited, ersetzt supports_topup. Unbekannte Werte: internal.invalid_filter (400).
data_min_bytesinteger · int64optionalMindestdatenvolumen in BYTES. Tagespakete werden anhand ihres TAGESVOLUMENS verglichen; unbegrenzte Pakete erfüllen IMMER eine Untergrenze.
data_max_bytesinteger · int64optionalMaximales Datenvolumen in BYTES. Unbegrenzte Pakete sind AUSGESCHLOSSEN, da eine Obergrenze für unbegrenzte Pakete nicht gilt und sonst bei der Suche nach kleinen Paketen erscheinen würde.
days_mininteger · int64optionalMindestgültigkeitsdauer in Tagen.
days_maxinteger · int64optionalHöchste Gültigkeitsdauer in Tagen.
price_mininteger · int64optionalMindestpreis (VND), verglichen mit dem Preis IHRER ORGANISATION. Der Filter wird NACH der serverseitigen Seitenauswahl angewendet. Kürzere Seiten bedeuten daher nicht das Datenende.
price_maxinteger · int64optionalHöchstpreis (VND), gleiche Regeln wie bei price_min.
network_genstringoptionalNur Pakete dieser Netzgeneration (2g | 3g | 4g | 5g). Unbekannte Werte führen zu internal.invalid_filter (400).
hotspotstringoptionaltruefalsetrue: Tethering ausdrücklich unterstützt; false: ausdrücklich nicht unterstützt. Ohne Angabe (features.hotspot = null) passt keines von beiden. Nur die Zeichenfolgen true und false sind erlaubt.
appstringoptionalNur Pakete, die diese App auf mindestens einem Betriebssystem AUSDRÜCKLICH unterstützen (app=tiktok). Fehlende Angaben erfüllen den Filter NICHT. Derzeit ist nur tiktok zulässig; andere Codes führen zu internal.invalid_filter (400).
voicestringoptionaltruefalsetrue: Telefonie ausdrücklich unterstützt; false: ausdrücklich nicht unterstützt. Ohne Angabe passt keines von beiden. Nur die Zeichenfolgen true und false sind erlaubt.
cursorstringoptionalSenden Sie next_cursor unverändert zurück. Stoppen Sie nur bei null, nicht bei kurzen Seiten: Schlüsselregeln, Organisationspreise und Preisfilter greifen nach dem Seitenschnitt. Der Cursor enthält den Filterfingerabdruck: Andere Filter oder beschädigte Daten ergeben catalog.cursor_mismatch (400), damit verschiedene Abfragen nicht vermischt werden.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
items | object[] | — | |
capabilities | object | Nachverkaufsfunktionen aus der tatsächlichen Paketdeklaration, nie vom Anbietertyp abgeleitet. Ohne Angaben sind alle Werte | |
cancel | object | — | |
restriction | string | kann null sein |
code_not_disclosednull |
supported | boolean | — | |
plan_change | object | — | |
policy | object | kann null sein | Verhalten des Anbieters beim AUFLADEN EINES NEUEN PAKETS. |
… | … | Tiefer verschachtelte Felder: siehe JSON-Beispiel. | |
supported | boolean | — | |
usage_check | object | — | |
supported | boolean | — | |
code | string | Paketcode aus IHREM Katalog, also | |
coverage | object | Nutzungsgebiete des Pakets. | |
countries | string[] | ISO-3166-Alpha-2-Codes. Leer für globale Pakete (keine Aufzählung von 200 Ländern) und Pakete ohne deklarierte Abdeckung. | |
country_count | integer | Anzahl abgedeckter Länder, um Mehrländerpakete ohne vollständigen Abruf und eigenes Zählen zu sortieren oder zu filtern. | |
group | string | Abdeckung: Länder ( | |
region | string | kann null sein | Immer |
data | object | Datenvolumen des Pakets. Alle Werte in BYTES, nicht MB/GB, um doppelte Rundung zu vermeiden. | |
daily_bytes | integer · int64 | kann null sein | TAGESDATENVOLUMEN in Bytes. |
label | string | Lesbare Bezeichnung aus derselben Funktion wie auf allen unseren Oberflächen. | |
model | string | Berechnungsart: dailyfixedunlimited | |
reset | object | kann null sein | Rücksetzzeit des Tagesvolumens, wichtig beim Kauf spät am Tag. |
at | string | kann null sein | Zurücksetzzeit in der lokalen Zeitzone |
note | string | kann null sein | — |
timezone | string | kann null sein | Zeitzone der Rücksetzung ( |
total_bytes | integer · int64 | kann null sein | Gesamtvolumen des Zeitraums in Bytes. |
description | string | kann null sein | Verkaufsbeschreibung des Pakets. |
description_en | string | kann null sein | Englische Beschreibung; |
features | object | Paketfunktionen als typisiertes Objekt statt Codeliste: | |
apps | object[] | App-Unterstützung nach BETRIEBSSYSTEM. Eine NICHT im Array vorhandene App bedeutet UNBEKANNT, nicht „funktioniert“. Nur gelistete Einträge sind Anbieterzusagen; derzeit ist nur TikTok angegeben. Es gibt bewusst kein zusammengefasstes Feld: Im echten Katalog unterstützen 2.465 Pakete TikTok auf dem iPhone, aber NICHT auf Android. Ein einziges Flag würde sie auf „nein“ reduzieren und fast ein Drittel des Katalogs falsch darstellen. | |
android | string |
supportedblockedunknown | |
app | string | App-Code in Kleinbuchstaben (z. B. | |
ios | string |
supportedblockedunknown | |
note | string | kann null sein | — |
hotspot | boolean | kann null sein | WLAN-Tethering für andere Geräte. |
kyc_required | boolean | kann null sein | Vor Nutzung ist eine Identitätsprüfung (KYC) erforderlich. |
sms | boolean | kann null sein | SMS. |
voice | boolean | kann null sein | Sprachanrufe. |
fup | object | kann null sein | Verhalten nach Verbrauch des Hochgeschwindigkeitsvolumens. |
behavior | string | kann null sein |
throttlecutoffnull |
high_speed_bytes | integer · int64 | kann null sein | Bytes bei voller Geschwindigkeit vor der Drosselung. |
note | string | kann null sein | — |
speed_kbps | integer | kann null sein | Geschwindigkeit NACH Verbrauch des schnellen Datenvolumens (kbps). |
market | string | VERSORGUNGSSYSTEM des Pakets, OFFENE Enumeration: unbekannte Werte ignorieren. Bestimmt Bestandsmodell und Nachverkaufsfunktionen. domesticinternational | |
name | string | — | |
name_en | string | kann null sein | Englischer Name; |
network | object | Netze, die das Paket nutzen kann. | |
apn | string | kann null sein | APN zur manuellen Eingabe auf bestimmten Android-Geräten ohne automatische Konfiguration. Für vollständige Installationshinweise und weniger Supportfälle erforderlich. |
carriers | object[] | Mobilfunkbetreiber, deren Netze das Paket nutzt. eSIM-Eigenschaft (Funknetz), nicht der Lieferant. | |
name | string | — | |
generations | string[] | kann null sein | Nutzbare Mobilfunkgenerationen ( |
speed_cap_kbps | integer | kann null sein | Geschwindigkeitslimit für das GESAMTE Paket (kbps), anders als |
price | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
tags | string[] | Normalisierte kommerzielle Tags (Kleinbuchstaben, Bindestriche), auch Grundlage der Katalogbeschränkungen Ihres Schlüssels. Derzeit trägt kein Paket Tags; | |
validity | object | Gültigkeitsdauer des Pakets und Beginn der Laufzeit. | |
days | integer | — | |
install_by_days | integer | kann null sein | Tage nach Kauf zum Scannen des QR-Codes bzw. Installieren der eSIM. |
label | string | — | |
reclaim_on_expiry | boolean | kann null sein | Der Anbieter zieht das Abonnement bei Ablauf zurück; Aufladen und Tarifwechsel sind danach unmöglich. Wichtig bei Verlängerungen. |
starts_when | string | kann null sein | Beginn der Laufzeit: on_installon_purchasenull |
unused_valid_days | integer | kann null sein | Anzahl der Tage, die ein Paket ungenutzt aufbewahrt werden kann, bevor es abläuft. |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
next_cursor | string | kann null sein | Für die nächste Seite UNVERÄNDERT zurücksenden. |
page_size | integer | kann null sein | MAXIMALE Datensatzanzahl, die der Server für diese Seite verwendet hat, bereits begrenzt. Nicht die tatsächliche Anzahl in |
total | integer · int64 | kann null sein | Anzahl passender Pakete; |
warnings | object[] | Erklärung der Liste; leer ohne Besonderheiten. Geschlossene Codes: | |
code | string | —filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing | |
count | integer · int64 | kann null sein | — |
message | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedinternal.invalid_filtercatalog.cursor_mismatchpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="GET"
REQ_PATH="/v1/catalog/packages" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"items": [
{
"capabilities": {
"cancel": {
"restriction": "code_not_disclosed",
"supported": true
},
"plan_change": {
"policy": {
"note": "<note>",
"requires_cancel_first": true,
"stacking": true
},
"supported": true
},
"usage_check": {
"supported": true
}
},
"code": "TKE-VN-30D-X3K9F",
"coverage": {
"countries": [
"CN"
],
"country_count": 1,
"group": "country",
"region": "<region>"
},
"data": {
"daily_bytes": 1073741824,
"label": "1GB/ngày",
"model": "daily",
"reset": {
"at": "00:00",
"note": "<note>",
"timezone": "UTC+8"
},
"total_bytes": null
},
"description": "<description>",
"description_en": "<description_en>",
"features": {
"apps": [
{
"android": "blocked",
"app": "tiktok",
"ios": "supported",
"note": "<note>"
}
],
"hotspot": true,
"kyc_required": false,
"sms": false,
"voice": false
},
"fup": {
"behavior": "throttle",
"high_speed_bytes": 1048576,
"note": "<note>",
"speed_kbps": 128
},
"market": "international",
"name": "eSIM Trung Quốc Mainland Multi - 1GB/ngày - 24 ngày",
"name_en": "<name_en>",
"network": {
"apn": "e-ideas",
"carriers": [
{
"name": "China Unicom"
}
],
"generations": [
"4g",
"5g"
],
"speed_cap_kbps": 1
},
"price": {
"amount": 273000,
"currency": "VND"
},
"tags": [],
"validity": {
"days": 24,
"install_by_days": 365,
"label": "24 ngày",
"reclaim_on_expiry": true,
"starts_when": "on_install",
"unused_valid_days": 1
}
}
],
"mode": "live",
"next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
"page_size": 50,
"total": 128,
"warnings": []
},
"ok": true
}/v1/catalog/packages/{code}Ein Paket abrufen
catalog:readget_catalog_packages__code_Erforderlicher Berechtigungsbereich: catalog:read.
Details GENAU EINES Pakets anhand des öffentlichen Codes. data enthält DIESELBEN FELDER wie ein Eintrag von GET /v1/catalog/packages, ergänzt um mode. Keine exklusiven Detailfelder; ein einziger Typ Package genügt.
Unsichtbare Codes führen zu partner.package_not_visible (404), unabhängig davon, ob der Code fehlt, außerhalb der Schlüsselbeschränkungen liegt, kein Organisationspreis vorliegt oder die Anbieterzuordnung fehlt. Unterschiedliche Fehler würden Fremden die Katalogaufzählung ermöglichen.
Pfadparameter (1)
codestringerforderlichPaketcode, im Katalog als code (public_sku). Pro Paket UNVERÄNDERLICH, auch bei Anbieterwechsel, und als Abgleichschlüssel speicherbar. Außerhalb der Schlüsselbeschränkungen oder ohne Organisationspreis: 404 partner.package_not_visible, wie bei nicht vorhandenem Code.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedpartner.package_not_visiblepartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
CODE="THAY-BANG-CODE"
METHOD="GET"
REQ_PATH="/v1/catalog/packages/$CODE" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": null,
"ok": true
}Bestellungen
Bestellungen aufgeben und abgleichen
/v1/ordersBestellungen auflisten (abfragebasierter Abgleich)
orders:readget_ordersErforderlicher Berechtigungsbereich: orders:read.
Query-Parameter (5)
page_sizeintegeroptionalStandard 50min 1max 200Datensätze pro Seite. Standard 50, höchstens 200. Höhere Werte werden ohne Fehler auf 200 begrenzt.
statusstringoptionalcompletedpending_providerprovider_failedcancelledNach Bestellstatus filtern. Werte außerhalb der Liste führen zu internal.invalid_filter (400).
external_refstringoptionalNach der beim Bestellabschluss gesendeten Referenz filtern (EXAKTE Übereinstimmung).
updated_sincestring · date-timeoptionalISO-8601 UTC. Liefert alle Datensätze mit updated_at >= updated_since in aufsteigender Reihenfolge. Dies ist der Standardweg für ABFRAGEBASIERTEN ABGLEICH (§8.5), auch bei verpassten Webhooks. Falsches Format: internal.invalid_filter (400).
cursorstringoptionalNächster Cursor: Senden Sie next_cursor unverändert zurück. Ein ungültiger Cursor beginnt ohne Fehler am Listenanfang, damit Änderungen der Codierung Integrationen nicht brechen. Prüfen Sie, ob der Cursor wechselt, um Endlosschleifen auf Seite eins zu vermeiden.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
items | object[] | — | |
created_at | string · date-time | — | |
external_ref | string | kann null sein | — |
fulfillment_status | string | —fulfilledpartially_fulfilledunfulfilled | |
id | string · uuid | — | |
item_count | integer · int64 | — | |
net | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
public_ref | string | kann null sein | — |
refunded | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
status | string | — | |
total | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
updated_at | string · date-time | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
next_cursor | string | kann null sein | Für die nächste Seite UNVERÄNDERT zurücksenden. |
page_size | integer | kann null sein | MAXIMALE Datensatzanzahl, die der Server für diese Seite verwendet hat, bereits begrenzt. Nicht die tatsächliche Anzahl in |
total | integer · int64 | kann null sein | Anzahl der zum Filter passenden Zeilen. |
warnings | object[] | Erklärung der Liste; leer ohne Besonderheiten. Geschlossene Codes: | |
code | string | —filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing | |
count | integer · int64 | kann null sein | — |
message | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedinternal.invalid_filterpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="GET"
REQ_PATH="/v1/orders" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"items": [
{
"created_at": "2026-07-11T08:12:30Z",
"external_ref": "po-1001",
"fulfillment_status": "fulfilled",
"id": "018f2b00-0000-7000-8000-00000000009a",
"item_count": 2,
"net": {
"amount": 273000,
"currency": "VND"
},
"public_ref": "TKE-DH-2A4C7Q",
"refunded": {
"amount": 273000,
"currency": "VND"
},
"status": "completed",
"total": {
"amount": 273000,
"currency": "VND"
},
"updated_at": "2026-07-11T09:03:11Z"
}
],
"mode": "live",
"next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
"page_size": 50,
"total": 128,
"warnings": []
},
"ok": true
}/v1/ordersBestellung erstellen (Direktkauf)
orders:writeIdempotency-Key erforderlichpost_ordersErforderlicher Berechtigungsbereich: orders:write.
Header (1)
Idempotency-KeystringerforderlichVom Client erzeugte Zeichenfolge: Gleicher Schlüssel und gleicher Body werden einmal ausgeführt; Wiederholungen liefern das erste Ergebnis. Gilt je api_key_id (§11): zwei Schlüssel sind getrennte Befehle.
Anfragetexterforderlichapplication/json
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
external_ref | string | kann null sein | Ihre eigene Referenz, unverändert in Antwort und Webhooks zurückgegeben. |
include | string[] | kann null sein | Zusatzblöcke: |
invoice_buyer | object | kann null sein | Nur Mitgliederschlüssel. Ohne Angaben gilt der Verbraucherablauf ohne Organisation oder vietnamesische juristische Person. Angaben folgen der Personenprüfung: full_name, persönliche 12-stellige tax_code und Checkout-Regeln für address/email. Geschäftsrechnungen werden nach dem Kauf beantragt. Im Testmodus wird nur der Snapshot geprüft, keine MISA-Rechnung ausgestellt. |
address | string | kann null sein | — |
email | string | kann null sein | — |
full_name | string | kann null sein | — |
legal_name | string | kann null sein | — |
tax_code | string | kann null sein | — |
items | object[] | erforderlich | Zu kaufende Pakete und Mengen (höchstens 50 eSIMs). |
package_code | string | erforderlich | Paketcode aus IHREM Katalog, also |
quantity | integer | erforderlich | Anzahl der für dieses Paket zu kaufenden eSIMs (≥ 1). |
Antwort
Wiederholung innerhalb von 24 Stunden mit gleichem Idempotency-Key und Body: IDENTISCHER Body, keine zweite Abbuchung, Header Idempotent-Replayed: true. Eine neue Ausführung liefert 201; erkennen Sie Erfolg nicht nur an diesem Status.
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | Partnerbestellung. |
created_at | string · date-time | — | |
external_ref | string | kann null sein | — |
fulfillment_status | string | Tatsächlich gelieferter Umfang, GETRENNT von fulfilledpartially_fulfilledunfulfilled | |
id | string · uuid | Bestell-ID (UUID). | |
idempotent_replay | boolean | kann null sein | Wahr, wenn diese Anfrage einen früheren Erfolg idempotent wiederholt. |
invoice_no | string | kann null sein | Rechnungsnummer nach Ausstellung. |
invoice_status | string | Status der Mehrwertsteuerrechnung zur Bestellung. nonependingissuingissuedfailedcancelled | |
items | object[] | — | |
cancellable | object | Stornierbarkeit der eSIM und Ablehnungsgrund; vor | |
allowed | boolean | — | |
disclosed_at | string · date-time | kann null sein | Zeitpunkt, zu dem der Code unser System verlassen hat (ISO-8601 UTC); |
reason | string | kann null sein | Stornierungsgrund: code_disclosedwrong_statusexpirednot_supportednull |
external_ref | string | kann null sein | Ihre Bestellreferenz ( |
iccid | string | kann null sein | — |
id | string · uuid | eSIM-ID für alle | |
install | object | kann null sein | Alle zur INSTALLATION dieser eSIM benötigten Daten. Eine Antwort mit diesem Block hat immer |
android_url | string | kann null sein | — |
apn | string | kann null sein | Zugangspunktname (APN), falls die automatische Einrichtung nicht erfolgt. In dieser Version IMMER |
ios_url | string | kann null sein | — |
lpa | string | kann null sein | Aktivierungscode der eSIM, ein verkäufliches Geheimnis. Diese Zeichenfolge genügt zum Erzeugen des QR-Codes. |
matching_id | string | kann null sein | — |
qr_code_base64 | string | kann null sein | QR-Code als PNG-Daten-URI. Nur mit |
smdp_address | string | kann null sein | — |
msisdn | string | kann null sein | — |
order_id | string · uuid | — | |
package_code | string | kann null sein | Paket-CODE aus dem Katalog als Zuordnungsschlüssel für diese eSIM. Nur |
package_name | string | Lesbarer Anzeigename, der sich ändern kann. NICHT als Abgleichschlüssel verwenden. | |
plan | object | kann null sein | Der aktuell für diese eSIM geltende Tarif. |
current_code | string | — | |
expires_at | string · date-time | kann null sein | — |
started_at | string · date-time | kann null sein | — |
smdp_status | string | kann null sein | — |
status | string | — | |
updated_at | string · date-time | — | |
usage | object | kann null sein | Datenverbrauchsstatistik der eSIM. |
expires_at | string · date-time | kann null sein | — |
remaining_bytes | integer · int64 | kann null sein | — |
source | string | kann null sein | —pollwebhook |
total_bytes | integer · int64 | kann null sein | — |
updated_at | string · date-time | kann null sein | — |
used_bytes | integer · int64 | kann null sein | — |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
money_settled | boolean | Ob die Bestellung vollständig abgerechnet ist, ohne laufende Erstattung. Bei | |
net | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
public_ref | string | kann null sein | Kurzer lesbarer Bestellcode für Supportanfragen. |
refunded | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
status | string | —completedpending_providerprovider_failedcancelled | |
total | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
ok | boolean | erforderlich | —true |
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | Partnerbestellung. |
created_at | string · date-time | — | |
external_ref | string | kann null sein | — |
fulfillment_status | string | Tatsächlich gelieferter Umfang, GETRENNT von fulfilledpartially_fulfilledunfulfilled | |
id | string · uuid | Bestell-ID (UUID). | |
idempotent_replay | boolean | kann null sein | Wahr, wenn diese Anfrage einen früheren Erfolg idempotent wiederholt. |
invoice_no | string | kann null sein | Rechnungsnummer nach Ausstellung. |
invoice_status | string | Status der Mehrwertsteuerrechnung zur Bestellung. nonependingissuingissuedfailedcancelled | |
items | object[] | — | |
cancellable | object | Stornierbarkeit der eSIM und Ablehnungsgrund; vor | |
allowed | boolean | — | |
disclosed_at | string · date-time | kann null sein | Zeitpunkt, zu dem der Code unser System verlassen hat (ISO-8601 UTC); |
reason | string | kann null sein | Stornierungsgrund: code_disclosedwrong_statusexpirednot_supportednull |
external_ref | string | kann null sein | Ihre Bestellreferenz ( |
iccid | string | kann null sein | — |
id | string · uuid | eSIM-ID für alle | |
install | object | kann null sein | Alle zur INSTALLATION dieser eSIM benötigten Daten. Eine Antwort mit diesem Block hat immer |
android_url | string | kann null sein | — |
apn | string | kann null sein | Zugangspunktname (APN), falls die automatische Einrichtung nicht erfolgt. In dieser Version IMMER |
ios_url | string | kann null sein | — |
lpa | string | kann null sein | Aktivierungscode der eSIM, ein verkäufliches Geheimnis. Diese Zeichenfolge genügt zum Erzeugen des QR-Codes. |
matching_id | string | kann null sein | — |
qr_code_base64 | string | kann null sein | QR-Code als PNG-Daten-URI. Nur mit |
smdp_address | string | kann null sein | — |
msisdn | string | kann null sein | — |
order_id | string · uuid | — | |
package_code | string | kann null sein | Paket-CODE aus dem Katalog als Zuordnungsschlüssel für diese eSIM. Nur |
package_name | string | Lesbarer Anzeigename, der sich ändern kann. NICHT als Abgleichschlüssel verwenden. | |
plan | object | kann null sein | Der aktuell für diese eSIM geltende Tarif. |
current_code | string | — | |
expires_at | string · date-time | kann null sein | — |
started_at | string · date-time | kann null sein | — |
smdp_status | string | kann null sein | — |
status | string | — | |
updated_at | string · date-time | — | |
usage | object | kann null sein | Datenverbrauchsstatistik der eSIM. |
expires_at | string · date-time | kann null sein | — |
remaining_bytes | integer · int64 | kann null sein | — |
source | string | kann null sein | —pollwebhook |
total_bytes | integer · int64 | kann null sein | — |
updated_at | string · date-time | kann null sein | — |
used_bytes | integer · int64 | kann null sein | — |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
money_settled | boolean | Ob die Bestellung vollständig abgerechnet ist, ohne laufende Erstattung. Bei | |
net | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
public_ref | string | kann null sein | Kurzer lesbarer Bestellcode für Supportanfragen. |
refunded | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
status | string | —completedpending_providerprovider_failedcancelled | |
total | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedinternal.invalid_filterpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedwallet.insufficient_balancepartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedpartner.package_not_visibleesim.out_of_stockidempotency.conflictinvoice.buyer_invalidpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="POST"
REQ_PATH="/v1/orders" # them query thi noi thang vao day TRUOC khi ky
BODY='{"external_ref":"po-1001","include":["lpa"],"invoice_buyer":{"address":"<address>","email":"<email>","full_name":"<full_name>","legal_name":"<legal_name>","tax_code":"TKE-VN-30D-X3K9F"},"items":[{"package_code":"TKE-VN-30D-X3K9F","quantity":2}]}'
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data-raw "$BODY"Beispielantwort
{
"data": {
"created_at": "2026-07-11T08:12:30Z",
"external_ref": "po-1001",
"fulfillment_status": "fulfilled",
"id": "018f2b00-0000-7000-8000-00000000009a",
"idempotent_replay": true,
"invoice_no": "<invoice_no>",
"invoice_status": "none",
"items": [
{
"cancellable": {
"allowed": true,
"disclosed_at": "2026-07-11T08:12:30Z",
"reason": "code_disclosed"
},
"external_ref": "po-1001",
"iccid": "8984012345678901234",
"id": "018f2b00-0000-7000-8000-00000000009a",
"install": {
"android_url": "https://esimsetup.google.com/esim_qrcode_provisioning?data=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
"apn": "<apn>",
"ios_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
"lpa": "LPA:1$smdp.example.com$MATCH-ABC123",
"matching_id": "MATCH-ABC123",
"qr_code_base64": "<PNG base64 — đã rút gọn>",
"smdp_address": "smdp.example.com"
},
"msisdn": "+84900000000",
"order_id": "018f2b00-0000-7000-8000-00000000009a",
"package_code": "TKE-VN-30D-X3K9F",
"package_name": "Tên gói hiển thị",
"plan": {
"current_code": "TKE-VN-30D-X3K9F",
"expires_at": "2026-08-10T00:00:00Z",
"started_at": "2026-07-11T08:12:30Z"
},
"smdp_status": "released",
"status": "delivered",
"updated_at": "2026-07-11T09:03:11Z",
"usage": {
"expires_at": "2026-08-10T00:00:00Z",
"remaining_bytes": 5368709120,
"source": "poll",
"total_bytes": 5368709120,
"updated_at": "2026-07-11T09:03:11Z",
"used_bytes": 5368709120
}
}
],
"mode": "live",
"money_settled": true,
"net": {
"amount": 273000,
"currency": "VND"
},
"public_ref": "TKE-DH-2A4C7Q",
"refunded": {
"amount": 273000,
"currency": "VND"
},
"status": "completed",
"total": {
"amount": 273000,
"currency": "VND"
}
},
"ok": true
}Beispiel-Anfragetext
{
"external_ref": "po-1001",
"include": [
"lpa"
],
"invoice_buyer": {
"address": "<address>",
"email": "<email>",
"full_name": "<full_name>",
"legal_name": "<legal_name>",
"tax_code": "TKE-VN-30D-X3K9F"
},
"items": [
{
"package_code": "TKE-VN-30D-X3K9F",
"quantity": 2
}
]
}/v1/orders/{id}Bestelldetails und eSIMs
orders:readget_orders__id_Erforderlicher Berechtigungsbereich: orders:read.
Pfadparameter (1)
idstringerforderlichBestell-ID (UUID).
Query-Parameter (1)
includestringoptionalKommagetrennte Zusatzblöcke: lpa liefert install, qr zusätzlich install.qr_code_base64 (nur Details). DIE CODEAUSGABE IST OFFENLEGUNG und beendet die Stornierbarkeit jeder betroffenen eSIM dauerhaft (cancellable.allowed = false, reason = code_disclosed). Fordern Sie den Code erst zur Lieferung an. Unbekannter Wert: internal.invalid_filter (400, field: "include").
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | Partnerbestellung. |
created_at | string · date-time | — | |
external_ref | string | kann null sein | — |
fulfillment_status | string | Tatsächlich gelieferter Umfang, GETRENNT von fulfilledpartially_fulfilledunfulfilled | |
id | string · uuid | Bestell-ID (UUID). | |
idempotent_replay | boolean | kann null sein | Wahr, wenn diese Anfrage einen früheren Erfolg idempotent wiederholt. |
invoice_no | string | kann null sein | Rechnungsnummer nach Ausstellung. |
invoice_status | string | Status der Mehrwertsteuerrechnung zur Bestellung. nonependingissuingissuedfailedcancelled | |
items | object[] | — | |
cancellable | object | Stornierbarkeit der eSIM und Ablehnungsgrund; vor | |
allowed | boolean | — | |
disclosed_at | string · date-time | kann null sein | Zeitpunkt, zu dem der Code unser System verlassen hat (ISO-8601 UTC); |
reason | string | kann null sein | Stornierungsgrund: code_disclosedwrong_statusexpirednot_supportednull |
external_ref | string | kann null sein | Ihre Bestellreferenz ( |
iccid | string | kann null sein | — |
id | string · uuid | eSIM-ID für alle | |
install | object | kann null sein | Alle zur INSTALLATION dieser eSIM benötigten Daten. Eine Antwort mit diesem Block hat immer |
android_url | string | kann null sein | — |
apn | string | kann null sein | Zugangspunktname (APN), falls die automatische Einrichtung nicht erfolgt. In dieser Version IMMER |
ios_url | string | kann null sein | — |
lpa | string | kann null sein | Aktivierungscode der eSIM, ein verkäufliches Geheimnis. Diese Zeichenfolge genügt zum Erzeugen des QR-Codes. |
matching_id | string | kann null sein | — |
qr_code_base64 | string | kann null sein | QR-Code als PNG-Daten-URI. Nur mit |
smdp_address | string | kann null sein | — |
msisdn | string | kann null sein | — |
order_id | string · uuid | — | |
package_code | string | kann null sein | Paket-CODE aus dem Katalog als Zuordnungsschlüssel für diese eSIM. Nur |
package_name | string | Lesbarer Anzeigename, der sich ändern kann. NICHT als Abgleichschlüssel verwenden. | |
plan | object | kann null sein | Der aktuell für diese eSIM geltende Tarif. |
current_code | string | — | |
expires_at | string · date-time | kann null sein | — |
started_at | string · date-time | kann null sein | — |
smdp_status | string | kann null sein | — |
status | string | — | |
updated_at | string · date-time | — | |
usage | object | kann null sein | Datenverbrauchsstatistik der eSIM. |
expires_at | string · date-time | kann null sein | — |
remaining_bytes | integer · int64 | kann null sein | — |
source | string | kann null sein | —pollwebhook |
total_bytes | integer · int64 | kann null sein | — |
updated_at | string · date-time | kann null sein | — |
used_bytes | integer · int64 | kann null sein | — |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
money_settled | boolean | Ob die Bestellung vollständig abgerechnet ist, ohne laufende Erstattung. Bei | |
net | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
public_ref | string | kann null sein | Kurzer lesbarer Bestellcode für Supportanfragen. |
refunded | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
status | string | —completedpending_providerprovider_failedcancelled | |
total | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedinternal.invalid_filterpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedinternal.not_foundpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="GET"
REQ_PATH="/v1/orders/$ID" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"created_at": "2026-07-11T08:12:30Z",
"external_ref": "po-1001",
"fulfillment_status": "fulfilled",
"id": "018f2b00-0000-7000-8000-00000000009a",
"idempotent_replay": true,
"invoice_no": "<invoice_no>",
"invoice_status": "none",
"items": [
{
"cancellable": {
"allowed": true,
"disclosed_at": "2026-07-11T08:12:30Z",
"reason": "code_disclosed"
},
"external_ref": "po-1001",
"iccid": "8984012345678901234",
"id": "018f2b00-0000-7000-8000-00000000009a",
"install": {
"android_url": "https://esimsetup.google.com/esim_qrcode_provisioning?data=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
"apn": "<apn>",
"ios_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
"lpa": "LPA:1$smdp.example.com$MATCH-ABC123",
"matching_id": "MATCH-ABC123",
"qr_code_base64": "<PNG base64 — đã rút gọn>",
"smdp_address": "smdp.example.com"
},
"msisdn": "+84900000000",
"order_id": "018f2b00-0000-7000-8000-00000000009a",
"package_code": "TKE-VN-30D-X3K9F",
"package_name": "Tên gói hiển thị",
"plan": {
"current_code": "TKE-VN-30D-X3K9F",
"expires_at": "2026-08-10T00:00:00Z",
"started_at": "2026-07-11T08:12:30Z"
},
"smdp_status": "released",
"status": "delivered",
"updated_at": "2026-07-11T09:03:11Z",
"usage": {
"expires_at": "2026-08-10T00:00:00Z",
"remaining_bytes": 5368709120,
"source": "poll",
"total_bytes": 5368709120,
"updated_at": "2026-07-11T09:03:11Z",
"used_bytes": 5368709120
}
}
],
"mode": "live",
"money_settled": true,
"net": {
"amount": 273000,
"currency": "VND"
},
"public_ref": "TKE-DH-2A4C7Q",
"refunded": {
"amount": 273000,
"currency": "VND"
},
"status": "completed",
"total": {
"amount": 273000,
"currency": "VND"
}
},
"ok": true
}/v1/orders/{id}/resendE-Mail bzw. QR-Code der Bestellung erneut senden
orders:writepost_orders__id__resendErforderlicher Berechtigungsbereich: orders:write.
Pfadparameter (1)
idstringerforderlichBestell-ID (UUID).
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
id | string · uuid | ID der soeben erneut gesendeten Bestellung. | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
resent_at | string · date-time | — | |
resent_to | string | Teilweise maskierte Empfängeradresse; die Partneroberfläche gibt die vollständige Kundenadresse nie erneut aus. | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedorder.not_deliverablepartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="POST"
REQ_PATH="/v1/orders/$ID/resend" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"id": "018f2b00-0000-7000-8000-00000000009a",
"mode": "live",
"resent_at": "2026-07-11T08:12:30Z",
"resent_to": "ab***@x.com"
},
"ok": true
}/v1/orders/bulkMehrzeiligen Auftrag ausführen (eine Bestellung pro Zeile)
orders:writeIdempotency-Key erforderlichpost_orders_bulkErforderlicher Berechtigungsbereich: orders:write.
Mehrzeilige Bestellung: Jede Zeile erzeugt eine unabhängige Bestellung mit quote→commit wie POST /v1/orders.
TEILERFOLG: Fehler einer Zeile blockieren andere nicht; nur erfolgreiche Zeilen werden belastet. Fachliche Fehler (ausverkauft, Guthabenmangel, nicht kaufbares Paket, Missbrauchsgrenze) stehen in lines[].error, ohne den HTTP-Status des Auftrags zu ändern. Nach Guthabenerschöpfung werden weitere Zeilen trotzdem versucht, da günstigere noch bezahlbar sein können.
Status immer 200: gemischte Zeilenergebnisse statt einer neu angelegten Einzelressource (201); vollständige Verarbeitung innerhalb der Anfrage, kein 202 mit Polling.
GLEICHER Idempotency-Key und GLEICHER Body laden den bestehenden Auftrag, liefern fertige Ergebnisse und verarbeiten nur pending-Zeilen weiter, ohne Doppelbelastung. Wurde keine Zeile ausgeführt, gilt Idempotent-Replayed: true. Gleicher Schlüssel mit anderem Body: idempotency.conflict.
Zwei inhaltlich identische Aufträge derselben Organisation innerhalb von 10 Minuten gelten auch mit unterschiedlichen Schlüsseln als versehentliches Duplikat: alter Auftrag mit Idempotent-Replayed: true, keine erneute Belastung. Für einen echten identischen Neukauf external_ref ändern. Es gehört zum signierten Inhalt und unterscheidet die Aufträge auch für den Abgleich. Vollständig fehlgeschlagene Aufträge (keine Bestellung erstellt) werden nie gesperrt; nach 10 Minuten ist eine neue identische Bestellung wieder möglich.
Zeilenreferenzen erscheinen in lines[].external_ref, die Auftragsreferenz oben in der Antwort.
Kein LPA/QR in der Antwort; je Bestellung GET /v1/orders/{order_id} abrufen.
Header (1)
Idempotency-KeystringerforderlichVom Client erzeugte Zeichenfolge: Gleicher Schlüssel und gleicher Body werden einmal ausgeführt; Wiederholungen liefern das erste Ergebnis. Gilt je api_key_id (§11): zwei Schlüssel sind getrennte Befehle.
Anfragetexterforderlichapplication/json
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
external_ref | string | kann null sein | Referenz für den GESAMTEN Auftrag, in der Auftragsantwort zurückgegeben. |
items | object[] | erforderlich | Jeder Eintrag erstellt eine unabhängige Bestellung. Konfigurierbares Zeilenlimit (Standard 100); Überschreitung: |
external_ref | string | kann null sein | Referenz nur für DIESE Zeile, unverändert im Zeilenergebnis zurückgegeben. |
package_code | string | erforderlich | Paketcode aus IHREM Katalog, also |
quantity | integer | erforderlich | — |
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | Ergebnis einer Sammelbestellung. TEILERFOLG: Fehlerhafte Zeilen blockieren andere nicht; nur |
created_at | string · date-time | — | |
external_ref | string | kann null sein | — |
failed_lines | integer | — | |
id | string · uuid | — | |
items | object[] | — | |
charged | object | kann null sein | — |
error | object | kann null sein | Echter Fehlercode |
code | string | — | |
message | string | — | |
external_ref | string | kann null sein | — |
line_no | integer | Ab 1, genau in der eingereichten Reihenfolge. | |
order_id | string · uuid | kann null sein | — |
package_code | string | — | |
quantity | integer | — | |
status | string | —pendingdonefailed | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
status | string |
pendingcompletedpartialfailed | |
succeeded_lines | integer | — | |
total_charged | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
total_lines | integer | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedpartner.package_not_visibleidempotency.conflictinternal.limit_exceededpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="POST"
REQ_PATH="/v1/orders/bulk" # them query thi noi thang vao day TRUOC khi ky
BODY='{"external_ref":"batch-2026-001","items":[{"external_ref":"po-1001","package_code":"TKE-VN-30D-X3K9F","quantity":5}]}'
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data-raw "$BODY"Beispielantwort
{
"data": {
"created_at": "2026-07-11T08:12:30Z",
"external_ref": "batch-2026-001",
"failed_lines": 1,
"id": "018f2b00-0000-7000-8000-00000000009a",
"items": [
{
"charged": null,
"error": {
"code": "TKE-VN-30D-X3K9F",
"message": "<message>"
},
"external_ref": "po-1001",
"line_no": 1,
"order_id": "018f2b00-0000-7000-8000-00000000009a",
"package_code": "TKE-VN-30D-X3K9F",
"quantity": 2,
"status": "pending"
}
],
"mode": "live",
"status": "pending",
"succeeded_lines": 1,
"total_charged": {
"amount": 273000,
"currency": "VND"
},
"total_lines": 1
},
"ok": true
}Beispiel-Anfragetext
{
"external_ref": "batch-2026-001",
"items": [
{
"external_ref": "po-1001",
"package_code": "TKE-VN-30D-X3K9F",
"quantity": 5
}
]
}/v1/orders/bulk/{id}Ergebnis einer Sammelbestellung
orders:readget_orders_bulk__id_Erforderlicher Berechtigungsbereich: orders:read.
Ergebnisse je Zeile eines bereits abgesendeten Auftrags erneut lesen, um eine verlorene Antwort ohne erneutes Senden des Bodys wiederherzustellen. Aufträge anderer Organisationen oder Umgebungen (Live/Test) führen zu 404.
Pfadparameter (1)
idstringerforderlichVon POST /v1/orders/bulk zurückgegebene Auftrags-ID (UUID).
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | Ergebnis einer Sammelbestellung. TEILERFOLG: Fehlerhafte Zeilen blockieren andere nicht; nur |
created_at | string · date-time | — | |
external_ref | string | kann null sein | — |
failed_lines | integer | — | |
id | string · uuid | — | |
items | object[] | — | |
charged | object | kann null sein | — |
error | object | kann null sein | Echter Fehlercode |
code | string | — | |
message | string | — | |
external_ref | string | kann null sein | — |
line_no | integer | Ab 1, genau in der eingereichten Reihenfolge. | |
order_id | string · uuid | kann null sein | — |
package_code | string | — | |
quantity | integer | — | |
status | string | —pendingdonefailed | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
status | string |
pendingcompletedpartialfailed | |
succeeded_lines | integer | — | |
total_charged | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
total_lines | integer | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedinternal.not_foundpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="GET"
REQ_PATH="/v1/orders/bulk/$ID" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"created_at": "2026-07-11T08:12:30Z",
"external_ref": "batch-2026-001",
"failed_lines": 1,
"id": "018f2b00-0000-7000-8000-00000000009a",
"items": [
{
"charged": null,
"error": {
"code": "TKE-VN-30D-X3K9F",
"message": "<message>"
},
"external_ref": "po-1001",
"line_no": 1,
"order_id": "018f2b00-0000-7000-8000-00000000009a",
"package_code": "TKE-VN-30D-X3K9F",
"quantity": 2,
"status": "pending"
}
],
"mode": "live",
"status": "pending",
"succeeded_lines": 1,
"total_charged": {
"amount": 273000,
"currency": "VND"
},
"total_lines": 1
},
"ok": true
}eSIM
eSIM-Datensätze, Verbrauch, Aufladung und Stornierung
/v1/esimseSIMs auflisten (abfragebasierter Abgleich)
esims:readget_esimsErforderlicher Berechtigungsbereich: esims:read.
Query-Parameter (8)
page_sizeintegeroptionalStandard 50min 1max 200Datensätze pro Seite. Standard 50, höchstens 200. Höhere Werte werden ohne Fehler auf 200 begrenzt.
statusstringoptionalpendingavailablereservedsolddeliveredin_useused_upexpiredsuspendedcancelledprovider_failedNach esim_status filtern. Unbekannte Werte führen zu internal.invalid_filter (400), nicht zu einer leeren Liste. Ein Tippfehler wie canceled statt cancelled darf nicht als fehlende eSIM missverstanden werden.
order_idstring · uuidoptionalNur eSIMs einer Bestellung.
iccidstringoptionalNach ICCID filtern (Zeichenfolge, exakte Übereinstimmung).
external_refstringoptionalAlle eSIMs der Bestellungen mit Ihrer Referenz external_ref (exakte Übereinstimmung).
updated_sincestring · date-timeoptionalISO-8601 UTC. Liefert alle Datensätze mit updated_at >= updated_since in aufsteigender Reihenfolge. Dies ist der Standardweg für ABFRAGEBASIERTEN ABGLEICH (§8.5), auch bei verpassten Webhooks. Falsches Format: internal.invalid_filter (400).
cursorstringoptionalNächster Cursor: Senden Sie next_cursor unverändert zurück. Ein ungültiger Cursor beginnt ohne Fehler am Listenanfang, damit Änderungen der Codierung Integrationen nicht brechen. Prüfen Sie, ob der Cursor wechselt, um Endlosschleifen auf Seite eins zu vermeiden.
includestringoptionalKommagetrennte Zusatzblöcke: lpa liefert install, qr zusätzlich install.qr_code_base64 (nur Details). DIE CODEAUSGABE IST OFFENLEGUNG und beendet die Stornierbarkeit jeder betroffenen eSIM dauerhaft (cancellable.allowed = false, reason = code_disclosed). Fordern Sie den Code erst zur Lieferung an. Unbekannter Wert: internal.invalid_filter (400, field: "include").
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
items | object[] | — | |
cancellable | object | Stornierbarkeit der eSIM und Ablehnungsgrund; vor | |
allowed | boolean | — | |
disclosed_at | string · date-time | kann null sein | Zeitpunkt, zu dem der Code unser System verlassen hat (ISO-8601 UTC); |
reason | string | kann null sein | Stornierungsgrund: code_disclosedwrong_statusexpirednot_supportednull |
external_ref | string | kann null sein | Ihre Bestellreferenz ( |
iccid | string | kann null sein | — |
id | string · uuid | eSIM-ID für alle | |
install | object | kann null sein | Alle zur INSTALLATION dieser eSIM benötigten Daten. Eine Antwort mit diesem Block hat immer |
android_url | string | kann null sein | — |
apn | string | kann null sein | Zugangspunktname (APN), falls die automatische Einrichtung nicht erfolgt. In dieser Version IMMER |
ios_url | string | kann null sein | — |
lpa | string | kann null sein | Aktivierungscode der eSIM, ein verkäufliches Geheimnis. Diese Zeichenfolge genügt zum Erzeugen des QR-Codes. |
matching_id | string | kann null sein | — |
qr_code_base64 | string | kann null sein | QR-Code als PNG-Daten-URI. Nur mit |
smdp_address | string | kann null sein | — |
msisdn | string | kann null sein | — |
order_id | string · uuid | — | |
package_code | string | kann null sein | Paket-CODE aus dem Katalog als Zuordnungsschlüssel für diese eSIM. Nur |
package_name | string | Lesbarer Anzeigename, der sich ändern kann. NICHT als Abgleichschlüssel verwenden. | |
plan | object | kann null sein | Der aktuell für diese eSIM geltende Tarif. |
current_code | string | — | |
expires_at | string · date-time | kann null sein | — |
started_at | string · date-time | kann null sein | — |
smdp_status | string | kann null sein | — |
status | string | — | |
updated_at | string · date-time | — | |
usage | object | kann null sein | Datenverbrauchsstatistik der eSIM. |
expires_at | string · date-time | kann null sein | — |
remaining_bytes | integer · int64 | kann null sein | — |
source | string | kann null sein | —pollwebhook |
total_bytes | integer · int64 | kann null sein | — |
updated_at | string · date-time | kann null sein | — |
used_bytes | integer · int64 | kann null sein | — |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
next_cursor | string | kann null sein | Für die nächste Seite UNVERÄNDERT zurücksenden. |
page_size | integer | kann null sein | MAXIMALE Datensatzanzahl, die der Server für diese Seite verwendet hat, bereits begrenzt. Nicht die tatsächliche Anzahl in |
total | integer · int64 | kann null sein | Anzahl der zum Filter passenden Zeilen. |
warnings | object[] | Erklärung der Liste; leer ohne Besonderheiten. Geschlossene Codes: | |
code | string | —filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing | |
count | integer · int64 | kann null sein | — |
message | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedinternal.invalid_filterpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="GET"
REQ_PATH="/v1/esims" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"items": [
{
"cancellable": {
"allowed": true,
"disclosed_at": "2026-07-11T08:12:30Z",
"reason": "code_disclosed"
},
"external_ref": "po-1001",
"iccid": "8984012345678901234",
"id": "018f2b00-0000-7000-8000-00000000009a",
"install": {
"android_url": "https://esimsetup.google.com/esim_qrcode_provisioning?data=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
"apn": "<apn>",
"ios_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
"lpa": "LPA:1$smdp.example.com$MATCH-ABC123",
"matching_id": "MATCH-ABC123",
"qr_code_base64": "<PNG base64 — đã rút gọn>",
"smdp_address": "smdp.example.com"
},
"msisdn": "+84900000000",
"order_id": "018f2b00-0000-7000-8000-00000000009a",
"package_code": "TKE-VN-30D-X3K9F",
"package_name": "Tên gói hiển thị",
"plan": {
"current_code": "TKE-VN-30D-X3K9F",
"expires_at": "2026-08-10T00:00:00Z",
"started_at": "2026-07-11T08:12:30Z"
},
"smdp_status": "released",
"status": "delivered",
"updated_at": "2026-07-11T09:03:11Z",
"usage": {
"expires_at": "2026-08-10T00:00:00Z",
"remaining_bytes": 5368709120,
"source": "poll",
"total_bytes": 5368709120,
"updated_at": "2026-07-11T09:03:11Z",
"used_bytes": 5368709120
}
}
],
"mode": "live",
"next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
"page_size": 50,
"total": 128,
"warnings": []
},
"ok": true
}/v1/esims/{id}Eine eSIM abrufen
esims:readget_esims__id_Erforderlicher Berechtigungsbereich: esims:read.
Pfadparameter (1)
idstringerforderlichStabile ID einer verkauften eSIM, nicht die wiederverwendbare ICCID.
Query-Parameter (1)
includestringoptionalKommagetrennte Zusatzblöcke: lpa liefert install, qr zusätzlich install.qr_code_base64 (nur Details). DIE CODEAUSGABE IST OFFENLEGUNG und beendet die Stornierbarkeit jeder betroffenen eSIM dauerhaft (cancellable.allowed = false, reason = code_disclosed). Fordern Sie den Code erst zur Lieferung an. Unbekannter Wert: internal.invalid_filter (400, field: "include").
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
cancellable | object | Stornierbarkeit der eSIM und Ablehnungsgrund; vor | |
allowed | boolean | — | |
disclosed_at | string · date-time | kann null sein | Zeitpunkt, zu dem der Code unser System verlassen hat (ISO-8601 UTC); |
reason | string | kann null sein | Stornierungsgrund: code_disclosedwrong_statusexpirednot_supportednull |
external_ref | string | kann null sein | Ihre Bestellreferenz ( |
iccid | string | kann null sein | — |
id | string · uuid | eSIM-ID für alle | |
install | object | kann null sein | Alle zur INSTALLATION dieser eSIM benötigten Daten. Eine Antwort mit diesem Block hat immer |
android_url | string | kann null sein | — |
apn | string | kann null sein | Zugangspunktname (APN), falls die automatische Einrichtung nicht erfolgt. In dieser Version IMMER |
ios_url | string | kann null sein | — |
lpa | string | kann null sein | Aktivierungscode der eSIM, ein verkäufliches Geheimnis. Diese Zeichenfolge genügt zum Erzeugen des QR-Codes. |
matching_id | string | kann null sein | — |
qr_code_base64 | string | kann null sein | QR-Code als PNG-Daten-URI. Nur mit |
smdp_address | string | kann null sein | — |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
msisdn | string | kann null sein | — |
order_id | string · uuid | — | |
package_code | string | kann null sein | Paket-CODE aus dem Katalog als Zuordnungsschlüssel für diese eSIM. Nur |
package_name | string | Lesbarer Anzeigename, der sich ändern kann. NICHT als Abgleichschlüssel verwenden. | |
plan | object | kann null sein | Der aktuell für diese eSIM geltende Tarif. |
current_code | string | — | |
expires_at | string · date-time | kann null sein | — |
started_at | string · date-time | kann null sein | — |
smdp_status | string | kann null sein | — |
status | string | — | |
updated_at | string · date-time | — | |
usage | object | kann null sein | Datenverbrauchsstatistik der eSIM. |
expires_at | string · date-time | kann null sein | — |
remaining_bytes | integer · int64 | kann null sein | — |
source | string | kann null sein | —pollwebhook |
total_bytes | integer · int64 | kann null sein | — |
updated_at | string · date-time | kann null sein | — |
used_bytes | integer · int64 | kann null sein | — |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedinternal.invalid_filterpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedinternal.not_foundpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="GET"
REQ_PATH="/v1/esims/$ID" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"cancellable": {
"allowed": true,
"disclosed_at": "2026-07-11T08:12:30Z",
"reason": "code_disclosed"
},
"external_ref": "po-1001",
"iccid": "8984012345678901234",
"id": "018f2b00-0000-7000-8000-00000000009a",
"install": {
"android_url": "https://esimsetup.google.com/esim_qrcode_provisioning?data=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
"apn": "<apn>",
"ios_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
"lpa": "LPA:1$smdp.example.com$MATCH-ABC123",
"matching_id": "MATCH-ABC123",
"qr_code_base64": "<PNG base64 — đã rút gọn>",
"smdp_address": "smdp.example.com"
},
"mode": "live",
"msisdn": "+84900000000",
"order_id": "018f2b00-0000-7000-8000-00000000009a",
"package_code": "TKE-VN-30D-X3K9F",
"package_name": "Tên gói hiển thị",
"plan": {
"current_code": "TKE-VN-30D-X3K9F",
"expires_at": "2026-08-10T00:00:00Z",
"started_at": "2026-07-11T08:12:30Z"
},
"smdp_status": "released",
"status": "delivered",
"updated_at": "2026-07-11T09:03:11Z",
"usage": {
"expires_at": "2026-08-10T00:00:00Z",
"remaining_bytes": 5368709120,
"source": "poll",
"total_bytes": 5368709120,
"updated_at": "2026-07-11T09:03:11Z",
"used_bytes": 5368709120
}
},
"ok": true
}/v1/esims/{id}/cancelUnbenutzte eSIM stornieren
esims:writeIdempotency-Key erforderlichpost_esims__id__cancelErforderlicher Berechtigungsbereich: esims:write.
Pfadparameter (1)
idstringerforderlichStabile ID einer verkauften eSIM, nicht die wiederverwendbare ICCID.
Header (1)
Idempotency-KeystringerforderlichVom Client erzeugte Zeichenfolge: Gleicher Schlüssel und gleicher Body werden einmal ausgeführt; Wiederholungen liefern das erste Ergebnis. Gilt je api_key_id (§11): zwei Schlüssel sind getrennte Befehle.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
cancelled_at | string · date-time | — | |
esim_id | string · uuid | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
refund_suggested | boolean |
| |
refunded | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
status | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedesim.not_cancellableidempotency.conflictcapability.not_supportedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="POST"
REQ_PATH="/v1/esims/$ID/cancel" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Idempotency-Key: $(uuidgen)"Beispielantwort
{
"data": {
"cancelled_at": "2026-07-11T08:12:30Z",
"esim_id": "018f2b00-0000-7000-8000-000000000000",
"mode": "live",
"refund_suggested": true,
"refunded": {
"amount": 273000,
"currency": "VND"
},
"status": "cancelled"
},
"ok": true
}/v1/esims/{id}/change-planeSIM aufladen
esims:writeIdempotency-Key erforderlichpost_esims__id__change-planErforderlicher Berechtigungsbereich: esims:write.
Pfadparameter (1)
idstringerforderlichStabile ID einer verkauften eSIM, nicht die wiederverwendbare ICCID.
Header (1)
Idempotency-KeystringerforderlichVom Client erzeugte Zeichenfolge: Gleicher Schlüssel und gleicher Body werden einmal ausgeführt; Wiederholungen liefern das erste Ergebnis. Gilt je api_key_id (§11): zwei Schlüssel sind getrennte Befehle.
Anfragetexterforderlichapplication/json
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
package_code | string | erforderlich | Paketcode aus IHREM Katalog, also |
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | Ergebnis des eSIM-Paketwechsels. |
charged | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
current_plan | object | — | |
code | string | — | |
expires_at | string · date-time | kann null sein | — |
started_at | string · date-time | kann null sein | — |
esim_id | string · uuid | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
order_id | string · uuid | — | |
previous_plan | object | kann null sein | — |
cancelled_at | string · date-time | kann null sein | — |
code | string | — | |
remaining_bytes_forfeited | integer · int64 | kann null sein | — |
warning | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedwallet.insufficient_balancepartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedpartner.package_not_visibleesim.topup_not_supportedesim.topup_provider_mismatchesim.not_eligibleidempotency.conflictcapability.not_supportedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="POST"
REQ_PATH="/v1/esims/$ID/change-plan" # them query thi noi thang vao day TRUOC khi ky
BODY='{"package_code":"TKE-VN-7D-P4M2Q"}'
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data-raw "$BODY"Beispielantwort
{
"data": {
"charged": {
"amount": 273000,
"currency": "VND"
},
"current_plan": {
"code": "TKE-VN-30D-X3K9F",
"expires_at": "2026-08-10T00:00:00Z",
"started_at": "2026-07-11T08:12:30Z"
},
"esim_id": "018f2b00-0000-7000-8000-000000000000",
"mode": "live",
"order_id": "018f2b00-0000-7000-8000-00000000009a",
"previous_plan": {
"cancelled_at": "2026-07-11T08:12:30Z",
"code": "TKE-VN-30D-X3K9F",
"remaining_bytes_forfeited": 2147483648
},
"warning": "Dung lượng còn lại của gói cũ KHÔNG được cộng dồn."
},
"ok": true
}Beispiel-Anfragetext
{
"package_code": "TKE-VN-7D-P4M2Q"
}/v1/esims/{id}/plan-optionsGültige Aufladepakete für diese eSIM
esims:readget_esims__id__plan-optionsErforderlicher Berechtigungsbereich: esims:read.
Liefert nur gültige Aufladepakete für GENAU DIESE eSIM. Der Anbieter wird aus der id ermittelt und entsprechend gefiltert. /v1 zeigt nirgends provider_id; der Server verhindert damit strukturell die Wahl eines Pakets eines anderen Anbieters. Ein nicht gelisteter Code bei POST /v1/esims/{id}/change-plan führt zu 409 esim.topup_provider_mismatch.
Ohne zugeordneten Anbieter (reiner Import oder fehlende Quelldaten) wird korrekt eine leere Liste (total: 0) zurückgegeben, kein Fehler.
Pfadparameter (1)
idstringerforderlichStabile ID einer verkauften eSIM, nicht die wiederverwendbare ICCID.
Query-Parameter (2)
page_sizeintegeroptionalStandard 50min 1max 200Datensätze pro Seite. Standard 50, höchstens 200. Höhere Werte werden ohne Fehler auf 200 begrenzt.
cursorstringoptionalNächster Cursor: Senden Sie next_cursor unverändert zurück. Ein ungültiger Cursor beginnt ohne Fehler am Listenanfang, damit Änderungen der Codierung Integrationen nicht brechen. Prüfen Sie, ob der Cursor wechselt, um Endlosschleifen auf Seite eins zu vermeiden.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | Für diese eSIM verfügbare Aufladepakete, nach ihrem Anbieter gefiltert. Jeder Eintrag ist ein vollständiges |
items | object[] | — | |
capabilities | object | Nachverkaufsfunktionen aus der tatsächlichen Paketdeklaration, nie vom Anbietertyp abgeleitet. Ohne Angaben sind alle Werte | |
cancel | object | — | |
restriction | string | kann null sein |
code_not_disclosednull |
supported | boolean | — | |
plan_change | object | — | |
policy | object | kann null sein | Verhalten des Anbieters beim AUFLADEN EINES NEUEN PAKETS. |
… | … | Tiefer verschachtelte Felder: siehe JSON-Beispiel. | |
supported | boolean | — | |
usage_check | object | — | |
supported | boolean | — | |
code | string | Paketcode aus IHREM Katalog, also | |
coverage | object | Nutzungsgebiete des Pakets. | |
countries | string[] | ISO-3166-Alpha-2-Codes. Leer für globale Pakete (keine Aufzählung von 200 Ländern) und Pakete ohne deklarierte Abdeckung. | |
country_count | integer | Anzahl abgedeckter Länder, um Mehrländerpakete ohne vollständigen Abruf und eigenes Zählen zu sortieren oder zu filtern. | |
group | string | Abdeckung: Länder ( | |
region | string | kann null sein | Immer |
data | object | Datenvolumen des Pakets. Alle Werte in BYTES, nicht MB/GB, um doppelte Rundung zu vermeiden. | |
daily_bytes | integer · int64 | kann null sein | TAGESDATENVOLUMEN in Bytes. |
label | string | Lesbare Bezeichnung aus derselben Funktion wie auf allen unseren Oberflächen. | |
model | string | Berechnungsart: dailyfixedunlimited | |
reset | object | kann null sein | Rücksetzzeit des Tagesvolumens, wichtig beim Kauf spät am Tag. |
at | string | kann null sein | Zurücksetzzeit in der lokalen Zeitzone |
note | string | kann null sein | — |
timezone | string | kann null sein | Zeitzone der Rücksetzung ( |
total_bytes | integer · int64 | kann null sein | Gesamtvolumen des Zeitraums in Bytes. |
description | string | kann null sein | Verkaufsbeschreibung des Pakets. |
description_en | string | kann null sein | Englische Beschreibung; |
features | object | Paketfunktionen als typisiertes Objekt statt Codeliste: | |
apps | object[] | App-Unterstützung nach BETRIEBSSYSTEM. Eine NICHT im Array vorhandene App bedeutet UNBEKANNT, nicht „funktioniert“. Nur gelistete Einträge sind Anbieterzusagen; derzeit ist nur TikTok angegeben. Es gibt bewusst kein zusammengefasstes Feld: Im echten Katalog unterstützen 2.465 Pakete TikTok auf dem iPhone, aber NICHT auf Android. Ein einziges Flag würde sie auf „nein“ reduzieren und fast ein Drittel des Katalogs falsch darstellen. | |
android | string |
supportedblockedunknown | |
app | string | App-Code in Kleinbuchstaben (z. B. | |
ios | string |
supportedblockedunknown | |
note | string | kann null sein | — |
hotspot | boolean | kann null sein | WLAN-Tethering für andere Geräte. |
kyc_required | boolean | kann null sein | Vor Nutzung ist eine Identitätsprüfung (KYC) erforderlich. |
sms | boolean | kann null sein | SMS. |
voice | boolean | kann null sein | Sprachanrufe. |
fup | object | kann null sein | Verhalten nach Verbrauch des Hochgeschwindigkeitsvolumens. |
behavior | string | kann null sein |
throttlecutoffnull |
high_speed_bytes | integer · int64 | kann null sein | Bytes bei voller Geschwindigkeit vor der Drosselung. |
note | string | kann null sein | — |
speed_kbps | integer | kann null sein | Geschwindigkeit NACH Verbrauch des schnellen Datenvolumens (kbps). |
market | string | VERSORGUNGSSYSTEM des Pakets, OFFENE Enumeration: unbekannte Werte ignorieren. Bestimmt Bestandsmodell und Nachverkaufsfunktionen. domesticinternational | |
name | string | — | |
name_en | string | kann null sein | Englischer Name; |
network | object | Netze, die das Paket nutzen kann. | |
apn | string | kann null sein | APN zur manuellen Eingabe auf bestimmten Android-Geräten ohne automatische Konfiguration. Für vollständige Installationshinweise und weniger Supportfälle erforderlich. |
carriers | object[] | Mobilfunkbetreiber, deren Netze das Paket nutzt. eSIM-Eigenschaft (Funknetz), nicht der Lieferant. | |
name | string | — | |
generations | string[] | kann null sein | Nutzbare Mobilfunkgenerationen ( |
speed_cap_kbps | integer | kann null sein | Geschwindigkeitslimit für das GESAMTE Paket (kbps), anders als |
price | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
tags | string[] | Normalisierte kommerzielle Tags (Kleinbuchstaben, Bindestriche), auch Grundlage der Katalogbeschränkungen Ihres Schlüssels. Derzeit trägt kein Paket Tags; | |
validity | object | Gültigkeitsdauer des Pakets und Beginn der Laufzeit. | |
days | integer | — | |
install_by_days | integer | kann null sein | Tage nach Kauf zum Scannen des QR-Codes bzw. Installieren der eSIM. |
label | string | — | |
reclaim_on_expiry | boolean | kann null sein | Der Anbieter zieht das Abonnement bei Ablauf zurück; Aufladen und Tarifwechsel sind danach unmöglich. Wichtig bei Verlängerungen. |
starts_when | string | kann null sein | Beginn der Laufzeit: on_installon_purchasenull |
unused_valid_days | integer | kann null sein | Anzahl der Tage, die ein Paket ungenutzt aufbewahrt werden kann, bevor es abläuft. |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
next_cursor | string | kann null sein | Für die nächste Seite UNVERÄNDERT zurücksenden. |
page_size | integer | MAXIMALE Datensatzanzahl, die der Server für diese Seite verwendet hat, bereits begrenzt. Nicht die tatsächliche Anzahl in | |
policy | object | kann null sein | Verhalten des Anbieters beim AUFLADEN EINES NEUEN PAKETS. |
note | string | kann null sein | — |
requires_cancel_first | boolean | Das LAUFENDE Paket wird vor Bestellung des neuen storniert, da dieser Anbieter Pakete nicht stapelt. Informieren Sie Kunden VOR dem Aufladen eines neuen Pakets. | |
stacking | boolean | Ob Laufzeit und Volumen des neuen Pakets zum laufenden addiert werden. | |
total | integer · int64 | kann null sein | Anzahl passender Pakete; |
warnings | object[] | Erklärung der Liste; leer ohne Besonderheiten. Geschlossene Codes: | |
code | string | —filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing | |
count | integer · int64 | kann null sein | — |
message | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedinternal.not_foundpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="GET"
REQ_PATH="/v1/esims/$ID/plan-options" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"items": [
{
"capabilities": {
"cancel": {
"restriction": "code_not_disclosed",
"supported": true
},
"plan_change": {
"policy": {
"note": "<note>",
"requires_cancel_first": true,
"stacking": true
},
"supported": true
},
"usage_check": {
"supported": true
}
},
"code": "TKE-VN-30D-X3K9F",
"coverage": {
"countries": [
"CN"
],
"country_count": 1,
"group": "country",
"region": "<region>"
},
"data": {
"daily_bytes": 1073741824,
"label": "1GB/ngày",
"model": "daily",
"reset": {
"at": "00:00",
"note": "<note>",
"timezone": "UTC+8"
},
"total_bytes": null
},
"description": "<description>",
"description_en": "<description_en>",
"features": {
"apps": [
{
"android": "blocked",
"app": "tiktok",
"ios": "supported",
"note": "<note>"
}
],
"hotspot": true,
"kyc_required": false,
"sms": false,
"voice": false
},
"fup": {
"behavior": "throttle",
"high_speed_bytes": 1048576,
"note": "<note>",
"speed_kbps": 128
},
"market": "international",
"name": "eSIM Trung Quốc Mainland Multi - 1GB/ngày - 24 ngày",
"name_en": "<name_en>",
"network": {
"apn": "e-ideas",
"carriers": [
{
"name": "China Unicom"
}
],
"generations": [
"4g",
"5g"
],
"speed_cap_kbps": 1
},
"price": {
"amount": 273000,
"currency": "VND"
},
"tags": [],
"validity": {
"days": 24,
"install_by_days": 365,
"label": "24 ngày",
"reclaim_on_expiry": true,
"starts_when": "on_install",
"unused_valid_days": 1
}
}
],
"mode": "live",
"next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
"page_size": 50,
"policy": {
"note": "<note>",
"requires_cancel_first": true,
"stacking": true
},
"total": 128,
"warnings": []
},
"ok": true
}/v1/esims/{id}/refund-requestsVerlauf der eSIM-Erstattungsanträge (nur Mitglieder)
esims:readget_esims__id__refund-requestsErforderlicher Berechtigungsbereich: esims:read.
Nur freigeschaltete Live-Mitgliederschlüssel. Liefert bis zu 50 aktuelle Anträge für die eigene eSIM, neueste zuerst; next_cursor und total sind null. has_open_request zeigt eine offene Prüfung an. Organisations- und Testschlüssel erhalten capability.not_supported.
Pfadparameter (1)
idstringerforderlichStabile ID einer verkauften eSIM, nicht die wiederverwendbare ICCID.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
has_open_request | boolean | — | |
items | object[] | — | |
decided_at | string · date-time | kann null sein | — |
decision_note | string | kann null sein | — |
id | string · uuid | — | |
order_id | string · uuid | — | |
order_item_id | string · uuid | — | |
reason | string | — | |
refunded | object | kann null sein | — |
requested_at | string · date-time | — | |
status | string | —pendingapprovedrejected | |
suggested | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
next_cursor | string | kann null sein | Für die nächste Seite UNVERÄNDERT zurücksenden. |
page_size | integer | kann null sein | MAXIMALE Datensatzanzahl, die der Server für diese Seite verwendet hat, bereits begrenzt. Nicht die tatsächliche Anzahl in |
total | integer · int64 | kann null sein | Anzahl der zum Filter passenden Zeilen. |
warnings | object[] | Erklärung der Liste; leer ohne Besonderheiten. Geschlossene Codes: | |
code | string | —filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing | |
count | integer · int64 | kann null sein | — |
message | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedinternal.not_foundcapability.not_supportedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_member_live_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="GET"
REQ_PATH="/v1/esims/$ID/refund-requests" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"has_open_request": true,
"items": [
{
"decided_at": "2026-07-11T08:12:30Z",
"decision_note": "<decision_note>",
"id": "018f2b00-0000-7000-8000-00000000009a",
"order_id": "018f2b00-0000-7000-8000-00000000009a",
"order_item_id": "018f2b00-0000-7000-8000-000000000000",
"reason": "<reason>",
"refunded": null,
"requested_at": "2026-07-11T08:12:30Z",
"status": "pending",
"suggested": {
"amount": 273000,
"currency": "VND"
}
}
],
"mode": "live",
"next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
"page_size": 50,
"total": 128,
"warnings": []
},
"ok": true
}/v1/esims/{id}/refund-requestseSIM-Erstattungsantrag erstellen (nur Mitglieder)
esims:writeIdempotency-Key erforderlichpost_esims__id__refund-requestsErforderlicher Berechtigungsbereich: esims:write.
Nur freigeschaltete Live-Mitgliederschlüssel. Einen Erstattungsantrag für die eigene eSIM mit Idempotency-Key senden; Geld wird erst nach Freigabe übertragen. Organisations- und Testschlüssel erhalten capability.not_supported. Im Testmodus übt die eSIM-Stornierung eine Erstattung ins virtuelle Wallet.
Pfadparameter (1)
idstringerforderlichStabile ID einer verkauften eSIM, nicht die wiederverwendbare ICCID.
Header (1)
Idempotency-KeystringerforderlichVom Client erzeugte Zeichenfolge: Gleicher Schlüssel und gleicher Body werden einmal ausgeführt; Wiederholungen liefern das erste Ergebnis. Gilt je api_key_id (§11): zwei Schlüssel sind getrennte Befehle.
Anfragetexterforderlichapplication/json
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
reason | string | erforderlich | Erstattungsgrund mit 5 bis 1000 Zeichen nach Entfernen führender und nachfolgender Leerzeichen. |
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
decided_at | string · date-time | kann null sein | — |
decision_note | string | kann null sein | — |
id | string · uuid | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
order_id | string · uuid | — | |
order_item_id | string · uuid | — | |
reason | string | — | |
refunded | object | kann null sein | — |
requested_at | string · date-time | — | |
status | string | —pendingapprovedrejected | |
suggested | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedinternal.not_foundesim.refund_not_eligibleesim.refund_request_pendingidempotency.conflictcapability.not_supportedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_member_live_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="POST"
REQ_PATH="/v1/esims/$ID/refund-requests" # them query thi noi thang vao day TRUOC khi ky
BODY='{"reason":"<reason>"}'
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data-raw "$BODY"Beispielantwort
{
"data": {
"decided_at": "2026-07-11T08:12:30Z",
"decision_note": "<decision_note>",
"id": "018f2b00-0000-7000-8000-00000000009a",
"mode": "live",
"order_id": "018f2b00-0000-7000-8000-00000000009a",
"order_item_id": "018f2b00-0000-7000-8000-000000000000",
"reason": "<reason>",
"refunded": null,
"requested_at": "2026-07-11T08:12:30Z",
"status": "pending",
"suggested": {
"amount": 273000,
"currency": "VND"
}
},
"ok": true
}Beispiel-Anfragetext
{
"reason": "<reason>"
}/v1/esims/{id}/usageVerbrauchte Daten
esims:readget_esims__id__usageErforderlicher Berechtigungsbereich: esims:read.
Liest das verbrauchte und verbleibende Datenvolumen einer eSIM samt Zeitstempel updated_at der Werte (tatsächliche Aktualität). Bei einer eSIM eines Anbieters, der nur auf Anfrage abgefragt wird (derzeit SkyFi), stellt dieser Aufruf einen Scan in die Warteschlange und WARTET bis zu etwa 15 Sekunden auf das Ergebnis; die Antwort kann daher bis zu ~15 Sekunden dauern, und die Werte stammen aus dem soeben beendeten Scan. Schlägt der Scan fehl, liegt der letzte Scan derselben eSIM weniger als 15 Sekunden zurück oder läuft die Wartezeit ab, wird KEIN Fehler zurückgegeben: Es werden die zuletzt gespeicherten Werte geliefert, prüfen Sie updated_at. Andere Anbieter liefern gespeicherte Werte, die regelmäßig aktualisiert werden.
Pfadparameter (1)
idstringerforderlichStabile ID einer verkauften eSIM, nicht die wiederverwendbare ICCID.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
esim_id | string · uuid | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
usage | object | kann null sein | Datenverbrauchsstatistik der eSIM. |
expires_at | string · date-time | kann null sein | — |
remaining_bytes | integer · int64 | kann null sein | — |
source | string | kann null sein | —pollwebhook |
total_bytes | integer · int64 | kann null sein | — |
updated_at | string · date-time | kann null sein | — |
used_bytes | integer · int64 | kann null sein | — |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedcapability.not_supportedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="GET"
REQ_PATH="/v1/esims/$ID/usage" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"esim_id": "018f2b00-0000-7000-8000-000000000000",
"mode": "live",
"usage": {
"expires_at": "2026-08-10T00:00:00Z",
"remaining_bytes": 5368709120,
"source": "poll",
"total_bytes": 5368709120,
"updated_at": "2026-07-11T09:03:11Z",
"used_bytes": 5368709120
}
},
"ok": true
}Wallet
Wallet-Guthaben
/v1/wallet/balanceWallet-Guthaben
wallet:readget_wallet_balanceErforderlicher Berechtigungsbereich: wallet:read.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
available | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
balance | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
credit_limit | object | Geldbetrag: Einheitliches Format überall auf | |
amount | integer · int64 | Ganzzahl in der kleinsten Einheit von | |
currency | string | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="GET"
REQ_PATH="/v1/wallet/balance" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"available": {
"amount": 273000,
"currency": "VND"
},
"balance": {
"amount": 273000,
"currency": "VND"
},
"credit_limit": {
"amount": 273000,
"currency": "VND"
},
"mode": "live"
},
"ok": true
}Webhooks
Webhook-Konfiguration, Zustellprotokoll und Simulator
/v1/testmode/webhooks/fail-nextNächsten Webhook-Fehler simulieren (nur Testschlüssel)
webhook:managepost_testmode_webhooks_fail-nextErforderlicher Berechtigungsbereich: webhook:manage.
Anfragetexterforderlichapplication/json
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
count | integer | — |
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
endpoint_id | string · uuid | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
testmode_fail_next | integer | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbiddeninternal.not_foundpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="POST"
REQ_PATH="/v1/testmode/webhooks/fail-next" # them query thi noi thang vao day TRUOC khi ky
BODY='{"count":1}'
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Content-Type: application/json" \
--data-raw "$BODY"Beispielantwort
{
"data": {
"endpoint_id": "018f2b00-0000-7000-8000-000000000000",
"mode": "live",
"testmode_fail_next": 1
},
"ok": true
}Beispiel-Anfragetext
{
"count": 1
}/v1/testmode/webhooks/fireTest-Webhook-Ereignis senden (nur Testschlüssel)
webhook:managepost_testmode_webhooks_fireErforderlicher Berechtigungsbereich: webhook:manage.
Anfragetexterforderlichapplication/json
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | Das Feld | |
event_type | string | erforderlich | Zu simulierender Webhook-Ereignistyp. order.completedorder.failedesim.deliveredesim.activatedesim.usage_thresholdesim.expiringwallet.low_balancecatalog.updated |
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
delivery_id | string · uuid | — | |
event_id | string · uuid | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbiddenwebhook.not_configuredinternal.not_foundpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="POST"
REQ_PATH="/v1/testmode/webhooks/fire" # them query thi noi thang vao day TRUOC khi ky
BODY='{"data":{},"event_type":"order.completed"}'
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Content-Type: application/json" \
--data-raw "$BODY"Beispielantwort
{
"data": {
"delivery_id": "018f2b00-0000-7000-8000-000000000000",
"event_id": "018f3c00-0000-7000-8000-0000000000b0",
"mode": "live"
},
"ok": true
}Beispiel-Anfragetext
{
"data": {},
"event_type": "order.completed"
}/v1/webhooksWebhook-Endpunkte auflisten
webhook:manageget_webhooksErforderlicher Berechtigungsbereich: webhook:manage.
Nur Endpoints des aufrufenden Schlüssels. Kein Schlüssel sieht den Endpoint eines anderen, auch nicht innerhalb derselben Organisation (§5.11: Bindung an api_key_id, keine gemeinsame Nutzung durch Live und Test).
Noch nicht eingerichtet: 200 mit leerem Array, kein 404. Die Sammlung existiert immer, auch ohne Einträge.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
items | object[] | — | |
active | boolean |
| |
created_at | string · date-time | — | |
events | string[] | Leer = alles empfangen. | |
id | string · uuid | Endpoint-ID für | |
last_delivery_at | string · date-time | kann null sein | Letzte Zustellung über diesen Endpoint. |
secret_last4 | string | Letzte vier Zeichen des Webhook-Geheimnisses, um den verwendeten Signierschlüssel zu prüfen, ohne das Geheimnis erneut offenzulegen. Vollständig nur EINMAL bei Erstellung sichtbar. | |
url | string | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
next_cursor | string | kann null sein | Für die nächste Seite UNVERÄNDERT zurücksenden. |
page_size | integer | kann null sein | MAXIMALE Datensatzanzahl, die der Server für diese Seite verwendet hat, bereits begrenzt. Nicht die tatsächliche Anzahl in |
total | integer · int64 | kann null sein | Anzahl der zum Filter passenden Zeilen. |
warnings | object[] | Erklärung der Liste; leer ohne Besonderheiten. Geschlossene Codes: | |
code | string | —filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing | |
count | integer · int64 | kann null sein | — |
message | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="GET"
REQ_PATH="/v1/webhooks" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"items": [
{
"active": true,
"created_at": "2026-07-11T08:12:30Z",
"events": [
"order.completed"
],
"id": "018f2b00-0000-7000-8000-00000000009a",
"last_delivery_at": "2026-07-11T08:12:30Z",
"secret_last4": "a3f9",
"url": "https://partner.example.com/hooks/tke"
}
],
"mode": "live",
"next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
"page_size": 50,
"total": 128,
"warnings": []
},
"ok": true
}/v1/webhooksWebhook-Endpunkt erstellen
webhook:managepost_webhooksErforderlicher Berechtigungsbereich: webhook:manage.
Endpoint für den aufrufenden Schlüssel erstellen. Vor dem Speichern sendet der Server ein signiertes POST-ping an die URL (CHECK_HEALTH). Ohne 2xx wird nichts gespeichert: 422 webhook.health_check_failed. Nur öffentliche https-URLs; interne oder Metadaten-IP: 422 webhook.url_not_allowed.
webhook_secret wird GENAU EINMAL angezeigt und kann nicht erneut gelesen werden. Bei Verlust im Dashboard rotieren; das alte Geheimnis bleibt 24 Stunden parallel gültig (§8.4).
Existiert bereits ein Endpoint, gilt 409 webhook.already_configured, auch bei Pause (is_active: false). Pause erhält URL, Geheimnis und Protokoll. Für einen Neustart erst DELETE /v1/webhooks/{id}, dann neu erstellen.
Anfragetexterforderlichapplication/json
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
events | string[] | Leer = alles empfangen. Unbekannter Wert: 400 | |
url | string · uri | erforderlich | — |
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
active | boolean |
| |
created_at | string · date-time | — | |
events | string[] | Leer = alles empfangen. | |
health_check | string | —passed | |
id | string · uuid | Endpoint-ID für | |
last_delivery_at | string · date-time | kann null sein | Letzte Zustellung über diesen Endpoint. |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
secret_last4 | string | Letzte vier Zeichen des Webhook-Geheimnisses, um den verwendeten Signierschlüssel zu prüfen, ohne das Geheimnis erneut offenzulegen. Vollständig nur EINMAL bei Erstellung sichtbar. | |
url | string | — | |
webhook_secret | string | NUR EINMAL bei Erstellung angezeigt (Präfix | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedwebhook.already_configuredwebhook.health_check_failedwebhook.url_not_allowedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="POST"
REQ_PATH="/v1/webhooks" # them query thi noi thang vao day TRUOC khi ky
BODY='{"events":["order.completed"],"url":"https://partner.example.com/hooks/tke"}'
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Content-Type: application/json" \
--data-raw "$BODY"Beispielantwort
{
"data": {
"active": true,
"created_at": "2026-07-11T08:12:30Z",
"events": [
"order.completed"
],
"health_check": "passed",
"id": "018f2b00-0000-7000-8000-00000000009a",
"last_delivery_at": "2026-07-11T08:12:30Z",
"mode": "live",
"secret_last4": "a3f9",
"url": "https://partner.example.com/hooks/tke",
"webhook_secret": "<webhook secret — chỉ hiện đúng một lần>"
},
"ok": true
}Beispiel-Anfragetext
{
"events": [
"order.completed"
],
"url": "https://partner.example.com/hooks/tke"
}/v1/webhooks/{id}Einen Webhook-Endpunkt abrufen
webhook:manageget_webhooks__id_Erforderlicher Berechtigungsbereich: webhook:manage.
Pfadparameter (1)
idstringerforderlichWebhook-Endpunkt-ID (id aus POST /v1/webhooks oder GET /v1/webhooks).
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
active | boolean |
| |
created_at | string · date-time | — | |
events | string[] | Leer = alles empfangen. | |
id | string · uuid | Endpoint-ID für | |
last_delivery_at | string · date-time | kann null sein | Letzte Zustellung über diesen Endpoint. |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
secret_last4 | string | Letzte vier Zeichen des Webhook-Geheimnisses, um den verwendeten Signierschlüssel zu prüfen, ohne das Geheimnis erneut offenzulegen. Vollständig nur EINMAL bei Erstellung sichtbar. | |
url | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedwebhook.not_foundpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="GET"
REQ_PATH="/v1/webhooks/$ID" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"active": true,
"created_at": "2026-07-11T08:12:30Z",
"events": [
"order.completed"
],
"id": "018f2b00-0000-7000-8000-00000000009a",
"last_delivery_at": "2026-07-11T08:12:30Z",
"mode": "live",
"secret_last4": "a3f9",
"url": "https://partner.example.com/hooks/tke"
},
"ok": true
}/v1/webhooks/{id}Webhook-Endpunkt aktualisieren
webhook:manageput_webhooks__id_Erforderlicher Berechtigungsbereich: webhook:manage.
Pfadparameter (1)
idstringerforderlichWebhook-Endpunkt-ID (id aus POST /v1/webhooks oder GET /v1/webhooks).
Anfragetexterforderlichapplication/json
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
events | string[] | Leer = alles empfangen. Unbekannter Wert: 400 | |
url | string · uri | erforderlich | — |
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
active | boolean |
| |
created_at | string · date-time | — | |
events | string[] | Leer = alles empfangen. | |
id | string · uuid | Endpoint-ID für | |
last_delivery_at | string · date-time | kann null sein | Letzte Zustellung über diesen Endpoint. |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
secret_last4 | string | Letzte vier Zeichen des Webhook-Geheimnisses, um den verwendeten Signierschlüssel zu prüfen, ohne das Geheimnis erneut offenzulegen. Vollständig nur EINMAL bei Erstellung sichtbar. | |
url | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedwebhook.not_foundwebhook.health_check_failedwebhook.url_not_allowedpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="PUT"
REQ_PATH="/v1/webhooks/$ID" # them query thi noi thang vao day TRUOC khi ky
BODY='{"events":["order.completed"],"url":"https://partner.example.com/hooks/tke"}'
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Content-Type: application/json" \
--data-raw "$BODY"Beispielantwort
{
"data": {
"active": true,
"created_at": "2026-07-11T08:12:30Z",
"events": [
"order.completed"
],
"id": "018f2b00-0000-7000-8000-00000000009a",
"last_delivery_at": "2026-07-11T08:12:30Z",
"mode": "live",
"secret_last4": "a3f9",
"url": "https://partner.example.com/hooks/tke"
},
"ok": true
}Beispiel-Anfragetext
{
"events": [
"order.completed"
],
"url": "https://partner.example.com/hooks/tke"
}/v1/webhooks/{id}Webhook-Endpunkt entfernen (keine neuen Ereignisse mehr empfangen)
webhook:managedelete_webhooks__id_Erforderlicher Berechtigungsbereich: webhook:manage.
Das Entfernen des Endpoints beendet neue Ereignisse für den aufrufenden Schlüssel.
Das webhook_secret geht mit dem Endpoint verloren. Neuanlage mit POST /v1/webhooks erzeugt NEUE id und NEUES Geheimnis; die Verifikation muss angepasst werden. Für vorübergehende Unterbrechung bei gleichem Geheimnis Pause im Dashboard verwenden.
Das vollständige Zustellprotokoll bleibt zum Abgleich erhalten, die Einträge des entfernten Endpoints können aber nicht erneut gesendet werden.
Auf Wiederholung wartende pending-Zustellungen enden mit endpoint_disabled und bleiben im Protokoll (§8.5).
Fremde oder bereits entfernte id: 404 webhook.not_found, niemals stilles 200.
Pfadparameter (1)
idstringerforderlichWebhook-Endpunkt-ID (id aus POST /v1/webhooks oder GET /v1/webhooks).
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
deleted_at | string · date-time | — | |
id | string · uuid | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedwebhook.not_foundpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="DELETE"
REQ_PATH="/v1/webhooks/$ID" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"deleted_at": "2026-07-11T08:12:30Z",
"id": "018f2b00-0000-7000-8000-00000000009a",
"mode": "live"
},
"ok": true
}/v1/webhooks/deliveriesWebhook-Zustellprotokoll
webhook:manageget_webhooks_deliveriesErforderlicher Berechtigungsbereich: webhook:manage.
Query-Parameter (5)
pageintegeroptionalStandard 1min 1Seitennummer ab 1. Hinter dem Datenende: items: [] und das echte total (200, kein 404).
page_sizeintegeroptionalStandard 50min 1max 200Datensätze pro Seite. Standard 50, höchstens 200. Höhere Werte werden ohne Fehler auf 200 begrenzt.
event_typestringoptionalNach Ereignistyp filtern (siehe Webhook-Ereigniskatalog).
statusstringoptionalpendingdeliveredfailedNach Zustellstatus filtern. ?status=failed dient dem abfragebasierten Webhook-Abgleich (§13). Unbekannte Werte werden ohne Fehler IGNORIERT; das vollständige Protokoll wird zurückgegeben.
event_idstring · uuidoptionalAlle Zustellversuche eines Ereignisses, einschließlich Wiederholungen.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
items | object[] | — | |
attempts | integer | — | |
created_at | string · date-time | — | |
event_id | string · uuid | Kennung des EREIGNISSES. Wiederholung erzeugt eine NEUE Zustellung mit GLEICHER | |
event_type | string | — | |
id | string · uuid | — | |
last_attempt_at | string · date-time | kann null sein | — |
next_retry_at | string · date-time | kann null sein | — |
response_code | integer | kann null sein | — |
status | string | —pendingdeliveredfailed | |
webhook_id | string · uuid | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
next_cursor | string | kann null sein | Für die nächste Seite UNVERÄNDERT zurücksenden. |
page_size | integer | kann null sein | MAXIMALE Datensatzanzahl, die der Server für diese Seite verwendet hat, bereits begrenzt. Nicht die tatsächliche Anzahl in |
total | integer · int64 | kann null sein | Anzahl der zum Filter passenden Zeilen. |
warnings | object[] | Erklärung der Liste; leer ohne Besonderheiten. Geschlossene Codes: | |
code | string | —filtered_by_key_package_filtersfiltered_by_provider_scopeno_price_for_orgprice_filter_removed_rowsprovider_disabledcapability_missing | |
count | integer · int64 | kann null sein | — |
message | string | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedwebhook.not_configuredpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="GET"
REQ_PATH="/v1/webhooks/deliveries" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"items": [
{
"attempts": 3,
"created_at": "2026-07-11T08:12:30Z",
"event_id": "018f3c00-0000-7000-8000-0000000000b0",
"event_type": "order.completed",
"id": "018f2b00-0000-7000-8000-00000000009a",
"last_attempt_at": "2026-07-11T09:05:00Z",
"next_retry_at": "2026-07-11T09:10:00Z",
"response_code": 200,
"status": "pending",
"webhook_id": "018f2b00-0000-7000-8000-000000000000"
}
],
"mode": "live",
"next_cursor": "eyJ1cGRhdGVkX2F0IjoiMjAyNi0wNy0xMVQwODoxMjozMFoifQ",
"page_size": 50,
"total": 128,
"warnings": []
},
"ok": true
}/v1/webhooks/deliveries/{id}/replayWebhook erneut senden
webhook:managepost_webhooks_deliveries__id__replayErforderlicher Berechtigungsbereich: webhook:manage.
Pfadparameter (1)
idstringerforderlichID einer Webhook-Zustellung (items[].id aus GET /v1/webhooks/deliveries).
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
attempts | integer | — | |
created_at | string · date-time | — | |
event_id | string · uuid | Kennung des EREIGNISSES. Wiederholung erzeugt eine NEUE Zustellung mit GLEICHER | |
event_type | string | — | |
id | string · uuid | — | |
last_attempt_at | string · date-time | kann null sein | — |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
next_retry_at | string · date-time | kann null sein | — |
response_code | integer | kann null sein | — |
status | string | —pendingdeliveredfailed | |
webhook_id | string · uuid | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedwebhook.delivery_not_foundwebhook.not_configuredpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="POST"
REQ_PATH="/v1/webhooks/deliveries/$ID/replay" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"attempts": 3,
"created_at": "2026-07-11T08:12:30Z",
"event_id": "018f3c00-0000-7000-8000-0000000000b0",
"event_type": "order.completed",
"id": "018f2b00-0000-7000-8000-00000000009a",
"last_attempt_at": "2026-07-11T09:05:00Z",
"mode": "live",
"next_retry_at": "2026-07-11T09:10:00Z",
"response_code": 200,
"status": "pending",
"webhook_id": "018f2b00-0000-7000-8000-000000000000"
},
"ok": true
}Testmodus
Nur Testschlüssel tke_test_ oder tke_member_test_ auf api-testing verwenden. Eigene Test-eSIMs und Daten ohne echtes Guthaben oder Lieferanten simulieren. Der Mitgliedertestmodus unterstützt keine Webhooks, Sammelbestellungen oder Rückerstattungsanträge zur Prüfung.
/v1/testmode/esims/{id}/simulateLebenszyklus einer Test-eSIM simulieren (nur Testschlüssel)
esims:writepost_testmode_esims__id__simulateErforderlicher Berechtigungsbereich: esims:write.
Nur Testschlüssel tke_test_ oder tke_member_test_. Ein Szenario auf die eigene Test-eSIM anwenden: Verbrauch, Installation, Ablauf, Drosselung oder simulierte Ablehnung des nächsten Vorgangs. Der Body benötigt mindestens ein Feld; leer ergibt 422 testmode.invalid_scenario. Ergebnisse über GET /v1/esims/{id} und /usage wie im Live-Modus lesen. Tarifwechsel- und Stornoregeln werden gemeinsam genutzt; kein echter Lieferant wird aufgerufen.
Pfadparameter (1)
idstringerforderlichStabile ID einer verkauften eSIM, nicht die wiederverwendbare ICCID.
Anfragetexterforderlichapplication/json
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data_used_mb | integer · int64 | Bereits verbrauchte Daten in MB (binär, 1 MiB). Werte über dem Kontingent werden begrenzt: Das ist das Verbrauchsszenario, kein Fehler. | |
expire_at | string · date-time | Einen genauen Ablaufzeitpunkt festlegen (ISO-8601 UTC). | |
expire_now | boolean |
| |
provider_reject | boolean | Anbieterablehnung beim nächsten Vorgang simulieren (Aufladung/Stornierung). | |
status | string | TECHNISCHER Lebenszyklus des eSIM-Profils im Vokabular des Anbieters. Anders als der kommerzielle releasedinstalledenableddisabled | |
throttled | boolean |
|
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
cancellable | object | Stornierbarkeit der eSIM und Ablehnungsgrund; vor | |
allowed | boolean | — | |
disclosed_at | string · date-time | kann null sein | Zeitpunkt, zu dem der Code unser System verlassen hat (ISO-8601 UTC); |
reason | string | kann null sein | Stornierungsgrund: code_disclosedwrong_statusexpirednot_supportednull |
external_ref | string | kann null sein | Ihre Bestellreferenz ( |
iccid | string | kann null sein | — |
id | string · uuid | eSIM-ID für alle | |
install | object | kann null sein | Alle zur INSTALLATION dieser eSIM benötigten Daten. Eine Antwort mit diesem Block hat immer |
android_url | string | kann null sein | — |
apn | string | kann null sein | Zugangspunktname (APN), falls die automatische Einrichtung nicht erfolgt. In dieser Version IMMER |
ios_url | string | kann null sein | — |
lpa | string | kann null sein | Aktivierungscode der eSIM, ein verkäufliches Geheimnis. Diese Zeichenfolge genügt zum Erzeugen des QR-Codes. |
matching_id | string | kann null sein | — |
qr_code_base64 | string | kann null sein | QR-Code als PNG-Daten-URI. Nur mit |
smdp_address | string | kann null sein | — |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
msisdn | string | kann null sein | — |
order_id | string · uuid | — | |
package_code | string | kann null sein | Paket-CODE aus dem Katalog als Zuordnungsschlüssel für diese eSIM. Nur |
package_name | string | Lesbarer Anzeigename, der sich ändern kann. NICHT als Abgleichschlüssel verwenden. | |
plan | object | kann null sein | Der aktuell für diese eSIM geltende Tarif. |
current_code | string | — | |
expires_at | string · date-time | kann null sein | — |
started_at | string · date-time | kann null sein | — |
simulated | object | Simulierter Zustand nach Anwendung des Szenarios. | |
esim_state | string | TECHNISCHER Lebenszyklus der Test-eSIM. Live stammt er aus releasedinstalledenableddisabled | |
last_via | string | Ablauf, der sie zuletzt GEÄNDERT hat. open_apisimulateseed | |
via | string | Ablauf, der diese Test-eSIM ERSTELLT hat. open_apisimulateseed | |
smdp_status | string | kann null sein | — |
status | string | — | |
updated_at | string · date-time | — | |
usage | object | kann null sein | Datenverbrauchsstatistik der eSIM. |
expires_at | string · date-time | kann null sein | — |
remaining_bytes | integer · int64 | kann null sein | — |
source | string | kann null sein | —pollwebhook |
total_bytes | integer · int64 | kann null sein | — |
updated_at | string · date-time | kann null sein | — |
used_bytes | integer · int64 | kann null sein | — |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbiddeninternal.not_foundtestmode.invalid_scenariopartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
ID="THAY-BANG-ID"
METHOD="POST"
REQ_PATH="/v1/testmode/esims/$ID/simulate" # them query thi noi thang vao day TRUOC khi ky
BODY='{"data_used_mb":4096,"expire_at":"2026-07-11T08:12:30Z","expire_now":true,"provider_reject":true,"status":"enabled","throttled":true}'
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Content-Type: application/json" \
--data-raw "$BODY"Beispielantwort
{
"data": {
"cancellable": {
"allowed": true,
"disclosed_at": "2026-07-11T08:12:30Z",
"reason": "code_disclosed"
},
"external_ref": "po-1001",
"iccid": "8984012345678901234",
"id": "018f2b00-0000-7000-8000-00000000009a",
"install": {
"android_url": "https://esimsetup.google.com/esim_qrcode_provisioning?data=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
"apn": "<apn>",
"ios_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24smdp.example.com%24MATCH-ABC123",
"lpa": "LPA:1$smdp.example.com$MATCH-ABC123",
"matching_id": "MATCH-ABC123",
"qr_code_base64": "<PNG base64 — đã rút gọn>",
"smdp_address": "smdp.example.com"
},
"mode": "live",
"msisdn": "+84900000000",
"order_id": "018f2b00-0000-7000-8000-00000000009a",
"package_code": "TKE-VN-30D-X3K9F",
"package_name": "Tên gói hiển thị",
"plan": {
"current_code": "TKE-VN-30D-X3K9F",
"expires_at": "2026-08-10T00:00:00Z",
"started_at": "2026-07-11T08:12:30Z"
},
"simulated": {
"esim_state": "released",
"last_via": "open_api",
"via": "open_api"
},
"smdp_status": "released",
"status": "delivered",
"updated_at": "2026-07-11T09:03:11Z",
"usage": {
"expires_at": "2026-08-10T00:00:00Z",
"remaining_bytes": 5368709120,
"source": "poll",
"total_bytes": 5368709120,
"updated_at": "2026-07-11T09:03:11Z",
"used_bytes": 5368709120
}
},
"ok": true
}Beispiel-Anfragetext
{
"data_used_mb": 4096,
"expire_at": "2026-07-11T08:12:30Z",
"expire_now": true,
"provider_reject": true,
"status": "enabled",
"throttled": true
}/v1/testmode/resetTestdaten zurücksetzen (nur Testschlüssel)
orders:writepost_testmode_resetErforderlicher Berechtigungsbereich: orders:write.
Header (1)
Idempotency-KeystringoptionalAnfragetextoptionalapplication/json
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
reason | string | — |
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
esim_states_deleted | integer · int64 | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
order_items_deleted | integer · int64 | — | |
orders_deleted | integer · int64 | — | |
wallet_balance | integer · int64 | Test-Wallet-Guthaben NACH dem Zurücksetzen, immer 0. Das Hauptbuch wird NICHT gelöscht; eine Gegenbuchung setzt den Saldo auf null. | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbiddenpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="POST"
REQ_PATH="/v1/testmode/reset" # them query thi noi thang vao day TRUOC khi ky
BODY='{"reason":"Reset test data"}'
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data-raw "$BODY"Beispielantwort
{
"data": {
"esim_states_deleted": 1,
"mode": "live",
"order_items_deleted": 1,
"orders_deleted": 1,
"wallet_balance": 1
},
"ok": true
}Beispiel-Anfragetext
{
"reason": "Reset test data"
}/v1/testmode/seedBeispieldaten im Testmodus anlegen (nur Testschlüssel)
orders:writepost_testmode_seedErforderlicher Berechtigungsbereich: orders:write.
Header (1)
Idempotency-KeystringoptionalAntwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
already_seeded | boolean | — | |
esims_created | integer | — | |
mode | string | Umgebung des aufrufenden Schlüssels, entsprechend X-TKE-Mode. Organisationen verwenden tke_live_/tke_test_, Mitglieder tke_member_live_/tke_member_test_. Live- und Test-Hosts erzwingen den Schlüsselmodus. testlive | |
orders_created | integer | — | |
seeded | boolean | — | |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbiddentestmode.no_sellable_packagepartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="POST"
REQ_PATH="/v1/testmode/seed" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG" \
-H "Idempotency-Key: $(uuidgen)"Beispielantwort
{
"data": {
"already_seeded": true,
"esims_created": 1,
"mode": "live",
"orders_created": 1,
"seeded": true
},
"ok": true
}/v1/testmode/statusTestmodus-Übersicht (nur Testschlüssel)
esims:readget_testmode_statusErforderlicher Berechtigungsbereich: esims:read.
Antwort
Erfolg
| Feld | Typ | Einschränkungen | Beschreibung |
|---|---|---|---|
data | object | erforderlich | — |
base_url_testing | string | Host für den Testmodus. Nur Schlüssel mit tke_test_ oder tke_member_test_ verwenden; der Live-Host antwortet mit 403 partner.wrong_host. | |
capabilities | object | — | |
bulk_orders | boolean | — | |
cancel_refund | boolean | — | |
refund_requests | boolean | — | |
webhooks | boolean | — | |
checklist | object[] | Integrationsschritte werden aus tatsächlichen API-Aufrufen desselben Inhabers im Testmodus abgeleitet. Der Webhook-Schritt gilt nur für Organisationen. | |
done | boolean | — | |
label | string | — | |
last_at | string · date-time | kann null sein | — |
step | string | — | |
drift | object | Simulation des Datenverbrauchs: Aktivierung, Intervall und letzter Lauf. Schwellenwert-Webhooks werden nur für Organisationen mit Webhook-Unterstützung gesendet. | |
enabled | boolean | — | |
interval_secs | integer · int64 | — | |
last_run_at | string · date-time | kann null sein | — |
mode | string | —testlive | |
ready | boolean | Ob der Schlüsselinhaber alle unterstützten Prüfschritte abgeschlossen hat. Mitglieder benötigen keinen Webhook-Test. | |
sample_counts | object | — | |
test_esims | integer · int64 | — | |
test_orders | integer · int64 | — | |
seeded | boolean | Ob der Schlüsselinhaber bereits Testbestellungen und Test-eSIMs besitzt. | |
test_key_count | integer · int64 | — | |
wallet_balance | integer · int64 | Testguthaben in virtuellen VND für den Schlüsselinhaber, getrennt vom Live-Wallet. | |
webhook | object | — | |
endpoint_url | string | kann null sein | — |
fail_next | integer | — | |
status | string | kann null sein | — |
ok | boolean | erforderlich | —true |
Fehlerantworten
Alle Fehler liefern { ok: false, error } mit passendem HTTP-Status, nie 200. Details auf der Fehlercodeseite.
internal.validation_failedpartner.invalid_keypartner.invalid_signaturepartner.timestamp_expiredpartner.nonce_reusedpartner.ip_not_allowedpartner.scope_deniedpartner.key_suspendedpartner.key_revokedorg.suspendedtestmode.live_key_forbiddenpartner.rate_limitedpartner.endpoint_disabledinternal.service_unavailableBeispielaufruf
Alle Werte TKE-VN-30D-X3K9F sind zu ersetzen. Echte Tarifcodes erhalten Sie über GET /v1/catalog/packages.
#!/usr/bin/env bash
# Can: bash + openssl + uuidgen.
KEY_ID="tke_test_THAY-BANG-KEY-ID-CUA-BAN"
SECRET="THAY-BANG-SECRET-CUA-BAN"
METHOD="GET"
REQ_PATH="/v1/testmode/status" # them query thi noi thang vao day TRUOC khi ky
BODY=""
TS="$(date +%s000)" # epoch milliseconds
NONCE="$(uuidgen)"
BODY_HASH="$(printf '%s' "$BODY" | openssl dgst -sha256 -hex | awk '{print $NF}')"
SIGNING="$METHOD"$'\n'"$REQ_PATH"$'\n'"$TS"$'\n'"$NONCE"$'\n'"$BODY_HASH"
SIG="$(printf '%s' "$SIGNING" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}')"
curl -sS -X "$METHOD" "https://api-testing.tongkhoesim.com$REQ_PATH" \
-H "Accept-Language: de" \
-H "X-TKE-Key: $KEY_ID" \
-H "X-TKE-Timestamp: $TS" \
-H "X-TKE-Nonce: $NONCE" \
-H "X-TKE-Signature: $SIG"Beispielantwort
{
"data": {
"base_url_testing": "<base_url_testing>",
"capabilities": {
"bulk_orders": true,
"cancel_refund": true,
"refund_requests": true,
"webhooks": true
},
"checklist": [
{
"done": true,
"label": "<label>",
"last_at": "2026-07-11T08:12:30Z",
"step": "<step>"
}
],
"drift": {
"enabled": true,
"interval_secs": 1,
"last_run_at": "2026-07-11T08:12:30Z"
},
"mode": "test",
"ready": true,
"sample_counts": {
"test_esims": 1,
"test_orders": 1
},
"seeded": true,
"test_key_count": 1,
"wallet_balance": 1,
"webhook": {
"endpoint_url": "https://partner.example.com/hooks/tke",
"fail_next": 1,
"status": "completed"
}
},
"ok": true
}