KedaSMS

KedaSMS 개발자 빠른 시작

계정 준비부터 사용량 전략 설정까지 단계별로 SMS 통합을 완료합니다.

아래 버튼으로 원하는 언어 문서를 확인하세요.

프로덕션 환경 도메인

콘솔, 프런트엔드 프록시, 백엔드 서비스는 분리되어 배포됩니다. 온보딩 전에 다음 주소를 허용하세요.

1. 계정 준비

등록하고 이메일을 확인하면 콘솔이 API 키를 생성합니다.

  1. 기업 이메일로 KedaSMS 계정을 등록합니다.
  2. 이메일 인증 코드 확인 단계를 완료합니다.
  3. 콘솔에 로그인하여 API 키 및 계정 잔액을 확인합니다.

2. 첫 번째 SMS 발송

프런트엔드 프록시를 통해 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 및 이번 청구 금액이 반환되어 조정에 편리합니다.

3. 가격 및 커버리지 범위 동기화

두 인터페이스 모두 JSON을 반환하며 랜딩 페이지 또는 내부 대시보드에 직접 포함할 수 있습니다.

4. 일일 보호 설정

일일 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 및 콘솔 작업 모두 준수합니다.

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"
}

단축 링크 서비스

동일한 암호화 구조로 /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=="
}

AES-256-GCM 암호화 예제

다음 예시는 페이로드를 암호화하고 timestamp를 AAD로 추가한 뒤 HTTPS를 통해 프런트엔드 프록시에 POST 합니다.

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 표준 라이브러리)

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;

매 요청마다 12바이트 IV를 새로 생성하고 timestamp는 UTC 기준 Unix 초로 서버 시간과 ±5분 이내를 유지하세요.

5. 운영 강화

다음 모범 사례에 따라 채널의 안정성을 유지합니다.

고객 콘솔로 들어가기KedaSMS 엔지니어와 상담