K-OTP

OTP 검증

POST /v1/verify

POST https://api.k-otp.dev/v1/verify

개요

Checks a 6-digit code against issueId with one-time semantics. On success the issue transitions to verified and cannot be verified again. A wrong code consumes one attempt. Verification failures are returned as 200 with verified: false and a reasonCode (MISMATCH, MAX_ATTEMPTS, EXPIRED, ALREADY_VERIFIED, REPLACED, NOT_FOUND), not as HTTP errors.

Accepts pk_ public keys (browser, Origin must exactly match an allowed origin) or sk_ secret keys.

Test mode. A test issue (pk_test_/sk_test_ key) verifies with the fixed code 000000, except scenario 05, where every code is MISMATCH; scenario 04 expires 10 seconds after issue. Responses carry mode: 'test'.

Rate limits. The key's perKey rule (for pk_ keys the platform default when the key sets none), capped at the platform ceiling, is enforced after validation; an exceeded rule returns 429 with Retry-After and data.retryAfterMs.

인증

허용 키필요 scope대체 허용 scope
pk_ / sk_otp:verifyotp:read, *

요청 본문

필드타입필수설명
issueIdstring예issueId returned by POST /v1/issue.
codestring예The 6-digit numeric code the end user received.

응답 (200)

Verification result. Check verified; failures carry reasonCode.

필드타입필수설명
issueIdstring예
verifiedboolean예true only when the code matched an active, unexpired issue.
reasonCode"ALREADY_VERIFIED" | "EXPIRED" | "MAX_ATTEMPTS" | "MISMATCH" | "NOT_FOUND" | "REPLACED"Present when verified is false.
attemptsRemainingnumber예Verification attempts left after this call.
expiresAtstring예Expiry of the issue (RFC 3339).
verifiedAtstringWhen the issue was verified (RFC 3339), if it has been.
mode"live" | "test"Mode of the API key that made the request: live, or test for a pk_test_/sk_test_ key (simulated, no message sent, no credit used).

오류 응답

모든 오류는 { defined, code, status, message, data? } 형태입니다. 자세한 내용은 오류를 참고하세요.

상태code설명
400BAD_REQUESTinvalid payload, blank issueId, or code is not a 6-digit numeric string.
401UNAUTHORIZEDthe Authorization: Bearer credential is missing, malformed, inactive, or rejected by introspection.
403FORBIDDENthe credential lacks otp:verify (or an accepted alias), or a pk_ public key was sent without an Origin header / with an Origin that is not an exact match for one of the key's allowedOrigins.
409CONFLICTthe request conflicts with the current state of the resource.
429TOO_MANY_REQUESTSthe API key exceeded a rate limit. data.limit names the rule (perKey, or perKeyDaily for test keys) and data.policy whether it came from the key's own policy (key) or a platform limit (platform: the default for pk_ keys or the platform ceiling). Wait data.retryAfterMs milliseconds (the Retry-After header carries the same wait in seconds) before retrying; rejected requests do not consume the limit or a verification attempt.
500INTERNAL_SERVER_ERRORunexpected server failure. Undefined errors (defined: false) use the same envelope.
503SERVICE_UNAVAILABLEintrospection or a downstream dependency is unavailable, or the rate limiter is unavailable for a pk_ key (fail-closed, Retry-After set). Retry with backoff.

요청 예시

curl -X POST "https://api.k-otp.dev/v1/verify" \
  -H "Authorization: Bearer $KOTP_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"issueId":"0192f3c4-8b7a-7c3e-9a51-2f4d6e8b1a90","code":"123456"}'

이 페이지의 내용