API Documentation

고객의 Android 디바이스를 통해 SMS를 발송하는 Developer API입니다. 모든 메시지는 E2E 암호화되어 전송됩니다.

Base URL

https://api-2ue64mzmvq-du.a.run.app

📖 Overview

Developer API는 devKey 인증 방식을 사용하며, 모든 메시지는 encKey로 E2E 암호화됩니다.

핵심 개념

  • devKey: 사용자가 앱에서 생성한 6글자+ 개발자 키 (인증용)
  • encKey: 사용자가 만든 6글자+ 비밀번호 (암호화용)
  • E2E 암호화: 전화번호와 메시지를 PBKDF2 + AES-256-GCM으로 암호화
  • Webhook: 고객이 메시지를 수신하면 개발자 서버로 전달

📱 앱에서 설정 필요: 사용자는 앱의 "개발자 설정"에서 devKey 생성 및 encKey 설정 후, 이 정보를 개발자에게 전달해야 합니다.

🚀 Getting Started

API를 사용하기 전에 반드시 Android 앱에서 키를 발급받아야 합니다.

⚠️ 필수: 앱에서 키 발급 필요

개발자가 SMS를 보내려면 Android 앱이 설치된 디바이스에서 devKey와 encKey를 먼저 생성해야 합니다.

👤

시나리오 1: 본인 핸드폰

개발자 본인의 핸드폰을 사용하여 SMS를 발송하는 경우

1.

Android 앱 설치

Google Play Store에서 앱 다운로드

2.

개발자 설정 메뉴 진입

앱 → 설정 → 개발자 설정

3.

devKey 생성

6글자 이상의 개발자 키 생성

4.

encKey 설정

6글자 이상의 암호화 비밀번호 생성

5.

본인의 서버 코드에서 사용

devKey와 encKey를 환경변수로 저장

👥

시나리오 2: 고객 핸드폰

고객의 핸드폰을 통해 SMS를 발송하는 경우

1.

고객에게 앱 설치 요청

Android 기기가 필요함을 안내

2.

고객에게 키 발급 요청

개발자 설정에서 devKey, encKey 생성 요청

3.

고객으로부터 키 받기

안전한 방법(암호화 채팅 등)으로 전달받기

4.

서버에 키 저장

고객별로 devKey, encKey 관리

5.

고객 핸드폰으로 SMS 발송

API 호출 시 해당 고객의 키 사용

💡 devKey와 encKey의 차이

devKey

개발자 인증 키 (API 인증용)

• 어떤 개발자가 요청하는지 식별
• 서버에 저장되어 uid와 매핑됨
• 서버 간 통신에 사용 (상대적으로 덜 민감)

encKey

암호화 비밀번호 (E2E 암호화용)

• 전화번호와 메시지를 암호화
• 서버는 복호화 불가 (앱만 복호화 가능)
• 절대 타인에게 노출되면 안 됨 (매우 민감)

🔒 보안 주의사항

  • encKey는 절대 코드에 하드코딩하지 마세요 - 환경변수나 암호화된 설정 파일에 저장하세요
  • encKey는 HTTPS로만 전송 - 평문 채팅이나 이메일로 전송 금지
  • 고객별로 다른 키 사용 권장 - 한 키가 노출되어도 다른 고객은 안전
  • 정기적인 키 교체 - 주기적으로 키를 변경하여 보안 강화

🔐 Authentication

모든 API 요청은 devKey를 사용하여 인증합니다. 사용자가 앱에서 생성한 devKey를 요청 본문에 포함하세요.

devKey 사용 방법

{
  "devKey": "my_dev_key_123",
  "messages": [...]
}

devKey 규칙

  • ✅ 최소 6글자 이상
  • ✅ 영문, 숫자, 하이픈(-), 언더스코어(_) 사용 가능
  • ❌ 공백 및 특수문자 (/ \ . ~ * [ ]) 사용 불가
  • ❌ Firestore 문서 ID 규칙 준수 필요

🔒 Encryption

전화번호와 메시지는 사용자의 encKey로 암호화되어 전송됩니다. 앱이 복호화하여 실제 SMS를 발송합니다.

암호화 규격

1. 키 유도 (PBKDF2)

import hashlib

SALT = b"free_group_sms_salt"
ITERATIONS = 10000

enc_key = hashlib.pbkdf2_hmac(
  'sha256',
  enc_password.encode('utf-8'),
  SALT,
  ITERATIONS,
  dklen=32
)

2. 암호화 (AES-256-GCM)

from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import base64, os

def encrypt(plaintext: str, key: bytes) -> str:
  aesgcm = AESGCM(key)
  iv = os.urandom(12) # 12바이트 IV
  ciphertext = aesgcm.encrypt(iv, plaintext.encode(), None)

  # "IV:암호문" 형식 (콜론으로 구분)
  iv_b64 = base64.b64encode(iv).decode()
  cipher_b64 = base64.b64encode(ciphertext).decode()
  return f"{iv_b64}:{cipher_b64}"

3. 암호화 형식

"IV_base64:암호문_base64"

예시: abc123def456:xyz789ghi012jkl345...

⚠️ 중요: 앱과 동일한 SALT, ITERATIONS를 사용해야 합니다. 암호화 키 유도 방식이 다르면 복호화가 실패합니다.

📤 Send SMS

암호화된 메시지를 고객의 디바이스로 전송합니다.

POST/api/v1/developer/send

Request Body

{
  "devKey": "my_dev_key_123",
  "messages": [
    {
      "recipient": "IV_base64:encrypted_phone",
      "message": "IV_base64:encrypted_message",
      "imageUrl": "https://example.com/image.jpg"
    }
  ]
}
devKey
requiredstring

사용자가 생성한 개발자 키

messages
requiredarray

암호화된 메시지 배열

recipient
requiredstring

암호화된 전화번호 (E.164 형식 권장)

message
requiredstring

암호화된 메시지 본문

imageUrl
optionalstring

MMS 이미지 URL (암호화 불필요)

Response

{
  "success": true,
  "data": {
    "messageId": "batch_1234567890"
  },
  "message": "메시지가 발송 대기 중입니다"
}

Python Example

import hashlib, base64, os, requests
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

# 1. 키 유도
SALT = b"free_group_sms_salt"
ITERATIONS = 10000
enc_password = "my_secret_pass123"

enc_key = hashlib.pbkdf2_hmac(
    'sha256',
    enc_password.encode('utf-8'),
    SALT,
    ITERATIONS,
    dklen=32
)

# 2. 암호화 함수
def encrypt(plaintext: str, key: bytes) -> str:
    aesgcm = AESGCM(key)
    iv = os.urandom(12)
    ciphertext = aesgcm.encrypt(iv, plaintext.encode(), None)

    iv_b64 = base64.b64encode(iv).decode()
    cipher_b64 = base64.b64encode(ciphertext).decode()
    return f"{iv_b64}:{cipher_b64}"

# 3. SMS 발송
encrypted_phone = encrypt("+821012345678", enc_key)
encrypted_message = encrypt("인증번호는 123456입니다", enc_key)

response = requests.post(
    "https://api-2ue64mzmvq-du.a.run.app/api/v1/developer/send",
    json={
        "devKey": "my_dev_key_123",
        "messages": [{
            "recipient": encrypted_phone,
            "message": encrypted_message
        }]
    }
)

result = response.json()
if result["success"]:
    print("발송 성공:", result["data"]["messageId"])
else:
    print("발송 실패:", result["error"])

🔔 Webhook

사용자가 메시지를 수신하면 개발자 서버로 암호화된 메시지를 전송합니다.

Webhook 등록

POST/api/v1/developer/webhook
{
  "devKey": "my_dev_key_123",
  "webhookUrl": "https://your-server.com/webhook"
}

Webhook 페이로드

고객이 메시지를 수신하면 다음 형식으로 POST 요청이 전송됩니다:

{
  "messages": {
    "msg_id_1": {
      "address": "IV:encrypted_phone",
      "body": "IV:encrypted_message",
      "type": "IV:encrypted_type",
      "date": "IV:encrypted_timestamp"
    }
  },
  "timestamp": 1736416234000
}

모든 필드가 암호화되어 있으므로 encKey로 복호화해야 합니다.

Webhook 삭제

DELETE/api/v1/developer/webhook?devKey=my_dev_key_123

📋 Response Format

모든 API는 표준 JSON 응답 형식을 사용합니다.

성공 응답

{
  "success": true,
  "data": {
    // 엔드포인트별 데이터
  },
  "message": "성공 메시지"  // optional
}

에러 응답

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "에러 메시지",
    "details": {}  // optional
  },
  "message": "에러 메시지"
}

⚠️ Error Codes

표준 에러 코드 및 HTTP 상태 코드입니다.

400

Bad Request

  • MISSING_REQUIRED_FIELD - 필수 필드 누락
  • INVALID_FORMAT - 잘못된 형식
  • INVALID_REQUEST - 유효하지 않은 요청
401

Unauthorized

  • UNAUTHORIZED - 인증 실패
  • INVALID_TOKEN - 유효하지 않은 토큰
  • TOKEN_EXPIRED - 토큰 만료
404

Not Found

  • NOT_FOUND - 리소스를 찾을 수 없음
  • USER_NOT_FOUND - 사용자를 찾을 수 없음
409

Conflict

  • ALREADY_EXISTS - 이미 존재하는 리소스
  • CONFLICT - 충돌 발생
500

Internal Server Error

  • INTERNAL_ERROR - 서버 내부 오류
  • DATABASE_ERROR - 데이터베이스 오류
  • EXTERNAL_SERVICE_ERROR - 외부 서비스 오류

시작하기

빠른 시작 가이드에서 5분 안에 첫 SMS를 발송해보세요.

Quick Start Guide →