SMS OTP API v1 · Production
문자 인증을
서비스에 연결하세요.
외부 서비스 서버에서 인증 요청을 만들고, 사용자를 일회용 인증 URL로 이동시킨 뒤, Callback에서 받은 1회용 결과 코드를 서버에서 교환하는 방식입니다.
Production endpoint
호출 주소
운영 환경의 모든 API 호출은 아래 도메인을 기준으로 합니다.
https://smsotp.imtdot.krhttps://smsotp.imtdot.kr
| 용도 | Method | 전체 URL |
|---|---|---|
| 인증 요청 생성 | POST | https://smsotp.imtdot.kr/api/v1/sessions |
| 사용자 인증 | GET | https://smsotp.imtdot.kr/v/{ONE_TIME_TOKEN} |
| 결과 코드 교환 | POST | https://smsotp.imtdot.kr/api/v1/results/exchange |
| 관리자 콘솔 | GET | https://smsotp.imtdot.kr/console/ |
| 개발자 문서 | GET | https://smsotp.imtdot.kr/dev/ |
| AI/Markdown 문서 | GET | https://smsotp.imtdot.kr/dev/guide.md |
Before integration
관리자 콘솔 준비
먼저 관리자 콘솔에서 서비스와 Callback을 등록하고 API Key/Secret을 발급하세요.
관리자 콘솔
https://smsotp.imtdot.kr/console/
서비스 이름: My Service
Client ID: my-service
Callback URL: https://service.example.com/auth/sms/callback
API Key: sms_live_...
API Secret: sms_secret_...
Step 1
인증 요청 생성
외부 서비스의 백엔드에서 이 API를 호출합니다. 브라우저에서 직접 호출하지 마세요.
https://smsotp.imtdot.kr/api/v1/sessionsRequest Headers
X-API-Key: sms_live_YOUR_KEY
X-API-Secret: sms_secret_YOUR_SECRET
Content-Type: application/json
Request Body
{
"callback_url": "https://service.example.com/auth/sms/callback",
"state": "6a9e09bd-17ea-4aa6-b82a-cb1f9ccd6a2e"
}
cURL 요청 예시
curl -X POST "https://smsotp.imtdot.kr/api/v1/sessions" \
-H "X-API-Key: sms_live_YOUR_KEY" \
-H "X-API-Secret: sms_secret_YOUR_SECRET" \
-H "Content-Type: application/json" \
--data '{
"callback_url": "https://service.example.com/auth/sms/callback",
"state": "6a9e09bd-17ea-4aa6-b82a-cb1f9ccd6a2e"
}'
성공 출력 예시 · HTTP 201
{
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"verification_url": "https://smsotp.imtdot.kr/v/5yR3lR4FM0uX6dQKpYxWf8YpM0zFQhX5",
"expires_in": 600,
"expires_at": "2026-08-30T01:20:00.000Z",
"session_reuse_enabled": true
}
| 응답 필드 | 설명 |
|---|---|
request_id | 인증 요청 식별자 |
verification_url | 사용자를 이동시킬 10분짜리 일회용 URL |
expires_in | URL 유효시간(초), 현재 600 |
expires_at | URL 만료 시각 |
session_reuse_enabled | 이 API Key가 7일 중앙 세션 재사용을 허용하는지 여부 |
Node.js / 서버 JavaScript
const SMS_OTP_BASE = 'https://smsotp.imtdot.kr';
const response = await fetch(`${SMS_OTP_BASE}/api/v1/sessions`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'X-API-Key': process.env.SMS_OTP_API_KEY,
'X-API-Secret': process.env.SMS_OTP_API_SECRET,
},
body: JSON.stringify({
callback_url: 'https://service.example.com/auth/sms/callback',
state: crypto.randomUUID(),
}),
});
const data = await response.json();
if (!response.ok) throw new Error(data.error);
// 사용자를 일회용 인증 URL로 이동
res.redirect(data.verification_url);
Step 2
사용자 인증 페이지
응답에서 받은 URL로 브라우저를 이동시킵니다. 토큰을 직접 만들어서는 안 됩니다.
GET https://smsotp.imtdot.kr/v/ONE_TIME_TOKENCentral session
7일 인증 세션
API Key 발급 시 기본적으로 세션 재사용이 켜져 있습니다.
기존 인증 재사용
같은 브라우저에서 최근 7일 이내 인증했다면 SMS를 다시 보내지 않고 바로 Callback으로 이동합니다.
매번 새 SMS OTP
API Key 설정에서 세션 허용을 끄면 기존 세션이 있어도 무시하고 매번 새로운 OTP 인증을 요구합니다.
세션 재사용 시 결과
{
"verification": {
"method": "existing_session"
}
}
Step 3
Callback 처리
인증 성공 후 등록된 Callback URL에 code와 원래의 state가 붙어서 돌아옵니다.
https://service.example.com/auth/sms/callback?code=result_A1B2C3D4&state=6a9e09bd-17ea-4aa6-b82a-cb1f9ccd6a2eCallback 서버 처리 예시
const { code, state } = req.query;
if (!code || !state || state !== req.session.smsOtpState) {
return res.status(400).send('Invalid callback state');
}
// 여기서 code를 결과 교환 API로 전송
Step 4
결과 코드 교환
Callback의 code 자체를 신뢰하지 말고 서버에서 최종 결과를 교환해야 합니다.
https://smsotp.imtdot.kr/api/v1/results/exchangeRequest Headers
X-API-Key: sms_live_YOUR_KEY
X-API-Secret: sms_secret_YOUR_SECRET
Content-Type: application/jsonRequest Body
{
"code": "result_A1B2C3D4"
}cURL 요청 예시
curl -X POST "https://smsotp.imtdot.kr/api/v1/results/exchange" \
-H "X-API-Key: sms_live_YOUR_KEY" \
-H "X-API-Secret: sms_secret_YOUR_SECRET" \
-H "Content-Type: application/json" \
--data '{"code":"result_A1B2C3D4"}'
성공 출력 · 이번에 SMS 인증
{
"verified": true,
"phone": "01012345678",
"verification": {
"method": "sms_otp",
"authenticated_at": "2026-08-30T00:42:15.000Z",
"session_expires_at": "2026-09-06T00:42:15.000Z"
}
}
성공 출력 · 7일 세션 재사용
{
"verified": true,
"phone": "01012345678",
"verification": {
"method": "existing_session",
"authenticated_at": "2026-08-30T00:42:15.000Z",
"session_expires_at": "2026-09-06T00:42:15.000Z"
}
}
Node.js 결과 교환
const response = await fetch('https://smsotp.imtdot.kr/api/v1/results/exchange', {
method: 'POST',
headers: {
'content-type': 'application/json',
'X-API-Key': process.env.SMS_OTP_API_KEY,
'X-API-Secret': process.env.SMS_OTP_API_SECRET,
},
body: JSON.stringify({ code }),
});
const result = await response.json();
if (!response.ok || result.verified !== true) {
throw new Error(result.error || 'SMS verification failed');
}
console.log(result.phone);
Full example
Express 전체 흐름
인증 시작부터 Callback 및 결과 교환까지 한 번에 보는 예시입니다.
Express / Node.js
import crypto from 'node:crypto';
const SMS_OTP_BASE = 'https://smsotp.imtdot.kr';
const CALLBACK_URL = 'https://service.example.com/auth/sms/callback';
app.get('/verify-phone', async (req, res) => {
const state = crypto.randomUUID();
req.session.smsOtpState = state;
const r = await fetch(`${SMS_OTP_BASE}/api/v1/sessions`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'X-API-Key': process.env.SMS_OTP_API_KEY,
'X-API-Secret': process.env.SMS_OTP_API_SECRET,
},
body: JSON.stringify({ callback_url: CALLBACK_URL, state }),
});
const data = await r.json();
if (!r.ok) return res.status(502).json(data);
return res.redirect(data.verification_url);
});
app.get('/auth/sms/callback', async (req, res) => {
const { code, state } = req.query;
if (!code || !state || state !== req.session.smsOtpState) {
return res.status(400).send('Invalid callback state');
}
delete req.session.smsOtpState;
const r = await fetch(`${SMS_OTP_BASE}/api/v1/results/exchange`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'X-API-Key': process.env.SMS_OTP_API_KEY,
'X-API-Secret': process.env.SMS_OTP_API_SECRET,
},
body: JSON.stringify({ code }),
});
const result = await r.json();
if (!r.ok || result.verified !== true) {
return res.status(400).json(result);
}
req.session.verifiedPhone = result.phone;
req.session.phoneVerified = true;
return res.redirect('/verification-complete');
});
Errors
오류 응답
API 오류는 JSON으로 반환됩니다. HTTP 상태 코드와 error 값을 함께 확인하세요.
API Key / Secret 오류 · 401
{
"error": "INVALID_API_CREDENTIALS"
}등록되지 않은 Callback · 403
{
"error": "INVALID_REDIRECT_URI"
}Callback 누락 · 400
{
"error": "CALLBACK_URL_REQUIRED"
}결과 code 오류/재사용
{
"error": "INVALID_OR_USED_CODE"
}| HTTP | 의미 |
|---|---|
200 | 정상 처리 |
201 | 인증 요청 생성 성공 |
400 | 요청 데이터 또는 결과 code 오류 |
401 | API Key/Secret 인증 실패 |
403 | 허용되지 않은 Callback 또는 정책 차단 |
410 | 인증 URL 만료 또는 이미 처리됨 |
500 | 서버 내부 오류 |
503 | 필수 서버 설정 누락 |
Security
연동 체크리스트
✓ API Key/Secret은 서버에서만 사용
✓ Callback은 HTTPS 사용
✓ Callback URL은 콘솔 등록값과 정확히 일치
✓ state는 매 요청마다 랜덤 생성
✓ state는 서버 세션/DB에 저장
✓ Callback에서 state를 반드시 비교
✓ code 자체만 보고 인증 성공 처리 금지
✓ /api/v1/results/exchange의 verified === true 확인
✓ 결과 code는 2분/1회용으로 취급
For AI agents
AI 에이전트용 문서
HTML을 파싱하기보다 canonical Markdown 문서를 직접 읽는 것을 권장합니다. Markdown에는 전체 호출 주소, 요청/출력 예시, 전체 흐름, 오류와 보안 규칙이 포함되어 있습니다.
https://smsotp.imtdot.kr/dev/guide.mdAI 문서 인덱스: https://smsotp.imtdot.kr/llms.txt