KedaSMS
계정 준비부터 사용량 전략 설정까지 단계별로 SMS 통합을 완료합니다.
아래 버튼으로 원하는 언어 문서를 확인하세요.
콘솔, 프런트엔드 프록시, 백엔드 서비스는 분리되어 배포됩니다. 온보딩 전에 다음 주소를 허용하세요.
https://www.kedasms.net
콘솔 및 공식 사이트 입구(KedaSMS 프론트엔드)https://www.kedasms.net/api
프런트엔드 프록시(/api/*) – 암호화된 요청을 받아 백엔드로 전달https://www.kedasms.net/docs
온라인 연결 가이드 및 API 문서등록하고 이메일을 확인하면 콘솔이 API 키를 생성합니다.
프런트엔드 프록시를 통해 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": "Success", "data": { "taskId": "20240408-0001", "message": "SMS task created", "debitedAmount": 0.048, "currency": "USD" } }
응답에는 작업 ID 및 이번 청구 금액이 반환되어 조정에 편리합니다.
두 인터페이스 모두 JSON을 반환하며 랜딩 페이지 또는 내부 대시보드에 직접 포함할 수 있습니다.
일일 SMS 및 지출 한도를 통해 예산 규정 준수를 보장합니다.
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 및 콘솔 작업 모두 준수합니다.
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 }
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" }
동일한 암호화 구조로 /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==" }
다음 예시는 페이로드를 암호화하고 timestamp를 AAD로 추가한 뒤 HTTPS를 통해 프런트엔드 프록시에 POST 합니다.
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분 이내를 유지하세요.
다음 모범 사례에 따라 채널의 안정성을 유지합니다.