두 개의 엔드포인트, 한 번의 왕복
호출이 MCP를 통한 AI 어시스턴트, HTTPS 외부 클라이언트, 또는 자체 백엔드에서 오더라도 동일한 로직이 적용됩니다.
send_otp
코드를 생성하고 유효 시간과 시도 카운터와 함께 해시를 저장한 다음, 페어링된 본인의 안드로이드를 통해 SMS를 발송합니다.
사용자가 코드를 수신
고객이 자신의 휴대폰에서 SMS를 확인하고 인증 폼에 코드를 입력합니다.
verify_otp
가장 최근에 발급한 코드와 상수 시간 비교를 수행합니다. verified 값과 실패 시 남은 시도 횟수를 반환합니다.
POST 전용, Bearer 인증
GET 요청은 405를 반환합니다. 쿠키는 무시됩니다. API 키가 URL이나 브라우저 히스토리에 남는 일은 없습니다.
발송 엔드포인트
POST https://app.sms8.io/ajax/otp-send.php
- phone, 필수, E.164 형식
- length, 4 ~ 8자리, 기본값 6
- expires_in, 60 ~ 900초, 기본값 300
- max_attempts, 1 ~ 10, 기본값 5
- template,
{code}플레이스홀더가 포함된 텍스트 - option / devices / useRandomDevice, 기기 선택
인증 엔드포인트
POST https://app.sms8.io/ajax/otp-verify.php
- phone, 필수, E.164 형식
- code, 사용자가 입력한 코드
응답:
- 성공 시
{verified: true} {verified: false, reason: "code_mismatch", attempts_left: 4}- 기타 사유:
expired,not_found,max_attempts
바로 복사해서 쓸 수 있는 호출
OTP 발송
curl -X POST https://app.sms8.io/ajax/otp-send.php \ -H "Authorization: Bearer YOUR_SMS8_API_KEY" \ -d "phone=+821012345678" # 기본값 재정의 : # -d "length=6" -d "expires_in=300" # -d "max_attempts=5" # -d "template=인증번호는 {code}입니다. 곧 만료됩니다." # 발신 기기 또는 SIM 선택 : # -d "option=0" --data-urlencode 'devices=["DEVICE_ID"]' # -d "option=1" # 모든 기기에 분산 # -d "option=2" # 모든 SIM에 분산 # -d "useRandomDevice=1" # 무작위 발신자 선택
코드 인증
curl -X POST https://app.sms8.io/ajax/otp-verify.php \ -H "Authorization: Bearer YOUR_SMS8_API_KEY" \ -d "phone=+821012345678" \ -d "code=123456" # 성공: {"verified": true} # 실패: {"verified": false, "reason": "code_mismatch", "attempts_left": 4}
AI 어시스턴트에서 (MCP)
Claude Code, Cursor 또는 Windsurf가 mcp.sms8.io에 연결되어 있다면 다음과 같이 요청하세요: "sms8 MCP를 통해 가입 플로우에 SMS 인증을 추가해줘". 어시스턴트는 기본값에 맞춰 send_otp와 verify_otp를 호출하고 기존 가입 또는 로그인 라우트에 통합합니다.
대시보드에서 한 번에 설정
기본값은 한 번만 설정하면 됩니다. 호출 시 필드를 비워두면 자동으로 적용됩니다. 고정된 한도는 어떠한 경우에도 유지됩니다.
코드 길이
4 ~ 8자리. 기본값 6. 기억하기 쉬울 만큼 짧고, 무차별 대입 공격에 견딜 만큼 깁니다.
유효 시간
60 ~ 900초. 기본값 300 (5분). 재사용을 제한할 만큼 짧고, 사용자가 입력할 시간은 충분합니다.
인증 시도 횟수
코드가 잠기기 전 1 ~ 10회 시도. 기본값 5.
재발송 쿨다운
동일 번호로의 발송 간 30 ~ 600초. 기본값 60.
SMS 템플릿
브랜드 톤에 맞게 문구를 조정하세요. 한 가지 제약은 {code} 플레이스홀더를 유지하는 것입니다.
고객을 보호하는 고정 한도
번호당 24시간 5개 OTP
가장 엄격한 한도입니다. 계정에서 변경할 수 없습니다. 키가 유출되어도 24시간 슬라이딩 윈도 내에서 어떤 번호도 5개를 초과해 받을 수 없습니다.
트랜잭션 검증
쿨다운과 24시간 한도는 SELECT ... FOR UPDATE 안에서 실행됩니다. 두 개의 병렬 호출이 한도를 우회할 수 없습니다.
상수 시간 인증
verify_otp는 hash_equals를 사용합니다. 타이밍 정보가 유출되지 않습니다.
POST 전용, 쿠키 없음
두 엔드포인트의 GET 요청은 405를 반환합니다. 인증에 쿠키는 사용되지 않습니다. 이미지 태그를 통한 CSRF가 불가능합니다.
OTP별 시도 한도
코드당 기본 5회 실패까지 허용됩니다. 그 이후에는 코드가 잠기고 새로운 send_otp가 필요합니다.
일반화된 오류 메시지
내부 예외는 Internal error를 반환합니다. 스택 트레이스가 클라이언트로 유출되지 않습니다.
OTP 관련 질문
SMS8로 OTP를 어떻게 보내나요?
전화번호와 함께 https://app.sms8.io/ajax/otp-send.php로 POST 요청을 보내세요. 엔드포인트는 Authorization: Bearer 헤더를 수용합니다. 선택 필드: length (4 ~ 8), expires_in (60 ~ 900초), max_attempts (1 ~ 10), template, 그리고 기기 선택자.
verify_otp는 어떻게 동작하나요?
전화번호와 사용자가 입력한 코드를 https://app.sms8.io/ajax/otp-verify.php로 POST하세요. 서버는 가장 최근 OTP와 상수 시간 비교를 수행하고 verified: true 또는 verified: false를 반환합니다. 실패 시 reason과 attempts_left도 함께 제공됩니다.
남용 방지 한도는 무엇인가요?
동일 번호는 24시간 슬라이딩 윈도 내 최대 5개의 OTP만 받습니다. 고정 한도이며, 계정에서 변경할 수 없고, 키가 유출되더라도 수신자를 보호합니다.
SMS8 OTP에 A2P 10DLC가 필요한가요?
아니요. SMS8은 페어링된 안드로이드와 SIM을 통해 OTP를 발송하므로 A2P 10DLC 등록이 필요하지 않습니다.
어시스턴트가 직접 OTP를 추가할 수 있나요?
네. Claude Code에 함께 제공되는 Skill이 어시스턴트에게 send_otp와 verify_otp를 언제 호출할지 학습시킵니다. "/signup에 인증을 추가해줘" 같은 프롬프트로 충분합니다.