모든 글로 돌아가기
가이드·2026-08-01·7 분 읽기

SMS 인증 자동화하기: API 완벽 가이드

API 키 발급부터 주문, 코드 폴링까지 — 실제로 동작하는 curl 예제와 요청 제한, 그리고 자주 걸려드는 함정까지 한 번에 정리했습니다.

가끔 가입할 때 몇 번 클릭하고 문자 한 통 기다리는 정도라면 웹사이트로 충분합니다. 하지만 자동화 테스트나 대량 가입 스크립트, CI 파이프라인, 혹은 사람 개입 없이 인증 코드를 받아야 하는 봇을 만들 때는 그걸로는 부족해집니다. 웹사이트로는 할 수 없지만 API로는 가능합니다. 이 글에서는 처음부터 실제로 동작하는 플로우를 만드는 데 필요한 모든 것을 다룹니다.

1단계: API 키 발급받기

로그인 후 /account/api-keys에서 키를 생성하세요. 키는 jm_ 뒤에 무작위 문자열이 붙는 형태입니다. 평문은 생성 시 단 한 번만 보여줍니다 — 저장되는 건 키 자체가 아니라 해시값이기 때문에, 분실 시 "키 복구"라는 옵션은 없습니다. 그냥 삭제하고 새로 만드세요.

모든 요청은 표준 Bearer 인증 방식을 사용합니다:

Authorization: Bearer jm_your_key

이 키는 비밀번호처럼 다뤄야 합니다 — 퍼블릭 저장소에 커밋하거나, 디버깅을 도와달라며 채팅창에 붙여넣지 마세요. 유출이 의심되면 /account/api-keys로 돌아가 삭제하고 새로 발급받으세요. 기존 키는 즉시 사용할 수 없게 됩니다.

2단계: 서비스와 국가 선택하기

주문하려면 두 가지가 필요합니다: service(서비스 코드)와 country(국가 id). 먼저 카탈로그를 조회해 보세요:

curl https://jiema.my/api/v1/services \
  -H "Authorization: Bearer jm_your_key"

각 항목에는 code 필드가 있습니다(Telegram이면 tg) — 이 값을 그대로 주문 엔드포인트에 넘기는 것이 직접 slug를 만드는 것보다 안전합니다. 특정 서비스의 국가별 실시간 가격과 재고를 보려면 service 파라미터를 추가하세요:

curl "https://jiema.my/api/v1/prices?service=tg" \
  -H "Authorization: Bearer jm_your_key"

items의 각 항목에는 countryId / priceCents / count(현재 사용 가능한 번호 수)가 들어 있습니다. 주문 전에 count를 확인하세요 — 0이면 주문이 실패할 게 뻔하니, 굳이 호출해서 몸으로 확인할 필요 없습니다.

3단계: 주문하기

curl -X POST https://jiema.my/api/v1/orders \
  -H "Authorization: Bearer jm_your_key" \
  -H "Content-Type: application/json" \
  -d '{"service":"tg","country":"6"}'

주문이 성공하면 전화번호와 만료 시각이 반환됩니다:

{
  "ok": true,
  "data": {
    "id": "cm...",
    "status": "WAITING",
    "phone": "62812xxxxxxx",
    "expiresAt": "2026-08-01T12:15:00.000Z",
    "chargedCents": "40"
  }
}

결제는 이 단계에서 이루어집니다 — chargedCents가 실제로 차감된 금액(센트 단위)입니다. 이 번호를 대상 앱에 입력해 인증 코드를 받고, 다음 단계로 넘어가세요.

4단계: 코드 폴링하기

WebSocket이나 webhook 푸시는 없습니다 — GET /api/v1/orders/:id를 계속 폴링하면서 smsBody가 더 이상 null이 아닐 때까지 기다려 SMS 내용을 받아옵니다:

while true; do
  RESP=$(curl -s https://jiema.my/api/v1/orders/$ORDER_ID \
    -H "Authorization: Bearer jm_your_key")
  BODY=$(echo "$RESP" | jq -r '.data.smsBody')
  if [ "$BODY" != "null" ]; then
    echo "Code received: $BODY"
    break
  fi
  sleep 5
done

5초 간격이면 무난한 시작점입니다 — 번호는 15분간 유효하고, 분당 60회인 조회 제한에도 여유가 충분합니다. 성격이 급하다면 3초도 괜찮습니다. 다만 1초마다 폴링한다고 코드가 더 빨리 오는 건 아니고, 요청 제한만 빨리 소진할 뿐입니다.

자주 걸리는 함정

  • 요청 제한은 키 단위가 아니라 사용자 단위입니다. 쓰기 계열 엔드포인트(order / cancel / next-sms)는 사용자당 분당 10회, 조회 계열은 분당 60회로 제한됩니다. 키를 여러 개 만들어도 한도가 늘어나지 않습니다 — 결국 같은 한도를 같이 씁니다.
  • 번호는 15분 후 만료됩니다. 코드를 받지 못한 채 만료된 미사용 번호는 자동으로 환불되므로 따로 요청할 필요는 없습니다. 다만 자체 파이프라인에서 번호를 실제로 쓰기까지 너무 오래 걸리면(예를 들어 큐에 걸려 대기하는 경우), 막상 쓰려고 할 때는 이미 죽어 있는 번호일 겁니다.
  • 하나의 번호로 여러 개의 코드를 받을 수 있습니다. 대상 앱이 SMS를 두 단계로 보낸다면(가입 확인 문자 하나, 그리고 별도의 로그인 코드), 첫 번째 코드를 받은 뒤 POST /api/v1/orders/:id/next-sms를 호출해 "이건 처리 끝났으니 계속 대기해 달라"고 알려주세요 — 새 번호를 받으려고 새로 주문할 필요가 없습니다.
  • 코드가 도착한 순간부터 취소는 동작하지 않습니다. POST /api/v1/orders/:id/cancel은 번호가 아직 코드를 기다리는 동안에는 즉시 환불해 주지만, smsBody가 한 번이라도 null이 아니었던 적이 있다면 같은 호출이 대신 CODE_RECEIVED 에러를 반환합니다 — 이미 지불한 만큼의 결과를 받은 것이므로 되돌릴 수 없습니다.
  • status를 한 번 확인하고 바로 포기하지 마세요. statusWAITING에서 RECEIVED로 바뀝니다. 만료될 때까지 계속 WAITING에 머물러 있다면 보통 해당 국가/서비스 조합의 수신율 문제인 경우가 많습니다 — 다른 국가로 새로 주문하는 쪽이 그냥 기다리는 것보다 대개 더 빨리 해결됩니다.

다음으로 살펴볼 것

여기까지가 주문부터 코드 수신까지의 핵심 흐름입니다. 모든 엔드포인트의 전체 필드 목록, 에러 코드, 예외 상황은 /api-docs에서 확인할 수 있습니다. 수십 개 계정의 인증 플로우를 동시에 유지하는 등 규모 있게 운영한다면, 각 주문의 폴링 루프를 독립적으로 타이밍을 맞춰야 합니다. 하나의 직렬 루프에 몰아넣고 순서대로 처리하면, 첫 번째 주문을 기다리는 동안 앞선 번호들이 먼저 만료되어 버립니다.

초대한 사용자의 주문마다 10% 적립

한도와 만료 없음. 링크를 공유하고 등록된 각 계정에 대해 평생 수수료를 받으세요.

내 링크 받기