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 分钟。
按照以下最佳实践保持通道稳定。