KedaSMS

KedaSMS developer quickstart

From account creation to usage policies, follow these steps to launch in minutes.

Χρησιμοποίησε τα παρακάτω κουμπιά για να δεις τον οδηγό σε άλλη γλώσσα.

Production domains

Traffic is separated between the console, the edge proxy and protected backends. Allow the following origins before onboarding.

1. Prepare your account

Sign up and verify your email address so the console can issue an API key.

  1. Register a KedaSMS account with your business email.
  2. Complete the email code verification step.
  3. Sign in to the console to view your API key and balance.

2. Send your first message

Submit AES-GCM encrypted payloads through the frontend proxy. Credit is reserved instantly and debited once the carrier confirms delivery.

POST https://www.kedasms.net/api/sms/send
Content-Type: application/json

{
  "apiKey": "your-api-key",
  "timestamp": 1712123456,
  "iv": "base64-iv==",
  "cipherText": "base64-ciphertext=="
}
{
  "code": "0",
  "message": "Success",
  "data": {
    "taskId": "20240408-0001",
    "message": "SMS task created",
    "debitedAmount": 0.048,
    "currency": "USD"
  }
}

The response includes the task ID and the amount debited from your account for full traceability.

3. Sync pricing & coverage

Both endpoints return JSON that can be embedded directly into your landing pages or BI dashboards.

4. Configure daily guardrails

Stay compliant with your budget by setting per-day SMS and spend caps.

PUT https://backup.kedasms.net/api/external/accounts/limits
Content-Type: application/json

{
  "apiKey": "your-api-key",
  "dailySmsCap": 5000,
  "dailySpendCap": 200,
  "alertThreshold": 0.8,
  "blockOnLimit": true
}

The limits apply to API-triggered sends and console campaigns in real time.

Status Query

Query SMS delivery status with real-time updates.

GET https://backup.kedasms.net/api/sms/status?msgid=msg_abc123def456

{
  "success": true,
  "data": {
    "msgid": "msg_abc123def456",
    "status": "DELIVERED",
    "recipient": "+12065550123",
    "sender": "KedaSMS",
    "message": "Your verification code is 123456",
    "sent_time": "2024-01-01T12:00:00Z",
    "delivered_time": "2024-01-01T12:00:05Z"
  },
  "code": 200
}

Callback Notification

Receive real-time notifications for SMS status changes, supporting status callbacks and link click callbacks.

POST https://backup.kedasms.net/api/sms/callback/KEDA
Content-Type: application/json

{
  "msgid": "msg_abc123def456",
  "status": "DELIVERED",
  "recipient": "+12065550123",
  "sender": "KedaSMS",
  "sent_time": "2024-01-01T12:00:00Z",
  "delivered_time": "2024-01-01T12:00:05Z",
  "cost": "0.05"
}

Short link service

Encrypt the short link payload the same way and call /api/shortlinks to obtain trackable URLs.

POST https://www.kedasms.net/api/shortlinks
Content-Type: application/json

{
  "apiKey": "your-api-key",
  "timestamp": 1712123456,
  "iv": "base64-iv==",
  "cipherText": "base64-ciphertext=="
}

AES-256-GCM encryption examples

Τα παρακάτω παραδείγματα κρυπτογραφούν το payload, προσθέτουν το timestamp ως AAD και το αποστέλλουν μέσω HTTPS στο frontend proxy.

Python (PyCryptodome)

import base64
import json
import os
import time
import requests
from Crypto.Cipher import AES

api_key = "your-api-key"
encryption_key = base64.b64decode("YOUR_ENCRYPTION_KEY_BASE64")

payload = {
    "countryCode": "CN",
    "phoneNumbers": ["13800138000"],
    "content": "您的验证码为 123456",
    "senderId": "KedaSMS",
    "trackClick": True,
    "callbackUrl": "https://example.com/webhook/sms"
}

iv = os.urandom(12)
timestamp = int(time.time())

cipher = AES.new(encryption_key, AES.MODE_GCM, nonce=iv)
cipher.update(timestamp.to_bytes(8, "big"))
ciphertext, tag = cipher.encrypt_and_digest(json.dumps(payload).encode("utf-8"))

body = {
    "apiKey": api_key,
    "timestamp": timestamp,
    "iv": base64.b64encode(iv).decode(),
    "cipherText": base64.b64encode(ciphertext + tag).decode()
}

response = requests.post(
    "https://www.kedasms.net/api/sms/send",
    json=body,
    timeout=10
)
response.raise_for_status()
print(response.json())

Java (JDK 17 standard library)

SecretKeySpec keySpec = new SecretKeySpec(Base64.getDecoder().decode("YOUR_ENCRYPTION_KEY_BASE64"), "AES");
byte[] iv = SecureRandom.getInstanceStrong().generateSeed(12);
long timestamp = Instant.now().getEpochSecond();

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, spec);
cipher.update(ByteBuffer.allocate(Long.BYTES).putLong(timestamp).array());

ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(payload);
byte[] encrypted = cipher.doFinal(json.getBytes(StandardCharsets.UTF_8));

Map<String, Object> body = Map.of(
        "apiKey", "your-api-key",
        "timestamp", timestamp,
        "iv", Base64.getEncoder().encodeToString(iv),
        "cipherText", Base64.getEncoder().encodeToString(encrypted)
);

String requestBody = objectMapper.writeValueAsString(body);
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://www.kedasms.net/api/sms/send"))
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(requestBody))
        .build();
HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

Go (crypto/aes + cipher.GCM)

package main

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/base64"
    "encoding/binary"
    "encoding/json"
    "log"
    "net/http"
    "time"
)

func main() {
    apiKey := "your-api-key"
    payload := map[string]any{
        "countryCode": "CN",
        "phoneNumbers": []string{"13800138000"},
        "content": "您的验证码为 123456",
        "senderId": "KedaSMS",
        "trackClick": true,
        "callbackUrl": "https://example.com/webhook/sms",
    }

    key, err := base64.StdEncoding.DecodeString("YOUR_ENCRYPTION_KEY_BASE64")
    if err != nil {
        log.Fatal(err)
    }
    iv := make([]byte, 12)
    if _, err := rand.Read(iv); err != nil {
        log.Fatal(err)
    }

    block, err := aes.NewCipher(key)
    if err != nil {
        log.Fatal(err)
    }
    gcm, err := cipher.NewGCM(block)
    if err != nil {
        log.Fatal(err)
    }

    timestamp := time.Now().Unix()
    aad := make([]byte, 8)
    binary.BigEndian.PutUint64(aad, uint64(timestamp))

    plaintext, err := json.Marshal(payload)
    if err != nil {
        log.Fatal(err)
    }
    ct := gcm.Seal(nil, iv, plaintext, aad)

    body := map[string]any{
        "apiKey":    apiKey,
        "timestamp": timestamp,
        "iv":        base64.StdEncoding.EncodeToString(iv),
        "cipherText": base64.StdEncoding.EncodeToString(ct),
    }

    bodyBytes, err := json.Marshal(body)
    if err != nil {
        log.Fatal(err)
    }

    req, err := http.NewRequest(http.MethodPost, "https://www.kedasms.net/api/sms/send", bytes.NewReader(bodyBytes))
    if err != nil {
        log.Fatal(err)
    }
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{Timeout: 10 * time.Second}
    resp, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    if resp.StatusCode >= 400 {
        log.Fatalf("unexpected status: %s", resp.Status)
    }
}

PHP (openssl + cURL)

<?php
$apiKey = 'your-api-key';
$encryptionKey = base64_decode('YOUR_ENCRYPTION_KEY_BASE64');

$payload = [
    'countryCode' => 'CN',
    'phoneNumbers' => ['13800138000'],
    'content' => '您的验证码为 123456',
    'senderId' => 'KedaSMS',
    'trackClick' => true,
    'callbackUrl' => 'https://example.com/webhook/sms',
];

$iv = random_bytes(12);
$timestamp = time();
$aad = pack('N2', $timestamp >> 32, $timestamp & 0xffffffff);

$ciphertext = openssl_encrypt(
    json_encode($payload, JSON_UNESCAPED_UNICODE),
    'aes-256-gcm',
    $encryptionKey,
    OPENSSL_RAW_DATA,
    $iv,
    $tag,
    $aad
);

if ($ciphertext === false) {
    throw new RuntimeException('encryption failed');
}

$body = [
    'apiKey' => $apiKey,
    'timestamp' => $timestamp,
    'iv' => base64_encode($iv),
    'cipherText' => base64_encode($ciphertext . $tag),
];

$ch = curl_init('https://www.kedasms.net/api/sms/send');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode($body),
    CURLOPT_TIMEOUT => 10,
]);

$response = curl_exec($ch);
if ($response === false) {
    throw new RuntimeException(curl_error($ch));
}

$httpStatus = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

if ($httpStatus >= 400) {
    throw new RuntimeException('unexpected status: ' . $httpStatus);
}

echo $response;

Δημιούργησε νέο IV 12 byte σε κάθε αίτημα και κράτησε το timestamp σε δευτερόλεπτα Unix UTC με απόκλιση ±5 λεπτών από την ώρα του διακομιστή.

5. Harden operations

Follow the operational best practices to keep delivery stable.

Open customer consoleTalk with a KedaSMS engineer