KedaSMS
從帳戶準備到用量策略設定,按步驟完成簡訊整合。
選擇下方語言按鈕即可切換到對應的在地化文件。
控制台、前端代理與後端服務分別部署,請在網路策略中放行以下位址。
https://www.kedasms.net控制台與官網入口(可達SMS 前端)https://www.kedasms.net/api前端代理入口(/api/*),負責接收加密請求並轉發至後端https://www.kedasms.net/docs線上接入指引與 API 文件註冊並驗證信箱,控制台才會生成 API Key。
透過前端代理提交 AES-GCM 加密請求,系統會預凍結餘額並在通道接收後自動扣費。
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": "成功",
"data": {
"taskId": "20240408-0001",
"message": "短信任务创建成功",
"debitedAmount": 0.056,
"currency": "USD"
}
}回應會返回任務 ID 以及本次扣費金額,便於核對。
兩個介面均返回 JSON,可直接嵌入落地頁或內部看板。
透過每日簡訊和花費上限確保預算合規。
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
}該限制即時生效,API 與控制台任務都會遵循。
查询短信发送状态,支持实时状态更新。
GET https://backup.kedasms.net/api/sms/status?msgid=msg_abc123def456
{
"success": true,
"data": {
"msgid": "msg_abc123def456",
"status": "DELIVERED",
"recipient": "+8613800138000",
"sender": "KedaSMS",
"message": "您的验证码为 123456",
"sent_time": "2024-01-01T12:00:00Z",
"delivered_time": "2024-01-01T12:00:05Z"
},
"code": 200
}接收短信状态变更的实时通知,支持状态回调和链接点击回调。
POST https://backup.kedasms.net/api/sms/callback/KEDA
Content-Type: application/json
{
"msgid": "msg_abc123def456",
"status": "DELIVERED",
"recipient": "+8613800138000",
"sender": "KedaSMS",
"sent_time": "2024-01-01T12:00:00Z",
"delivered_time": "2024-01-01T12:00:05Z",
"cost": "0.05"
}使用相同的加密結構呼叫 /api/shortlinks,可產生可追蹤的專屬短網址。
POST https://www.kedasms.net/api/shortlinks
Content-Type: application/json
{
"apiKey": "your-api-key",
"timestamp": 1712123456,
"iv": "base64-iv==",
"cipherText": "base64-ciphertext=="
}以下範例會先加密業務載荷並透過 HTTPS POST 到前端代理,同時將 timestamp 作為 AAD。
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())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());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
$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;請為每次請求產生新的 12 位元組 IV,並確保 timestamp 使用 UTC Unix 秒且與伺服器時間誤差不超過 5 分鐘。
按照以下最佳實踐保持通道穩定。