Get an OTP issue for the authenticated app
GET /v1/issues/{issueId}
GET https://api.k-otp.dev/v1/issues/{issueId}Overview
Returns the same PII-free projection as GET /issues for a single issue, including billing status and attempt counters. Issue identifiers belonging to other apps are indistinguishable from missing records.
Requires an sk_ secret key; pk_ public keys are rejected with 403.
Authentication
| Accepted keys | Required scope | Also accepted |
|---|---|---|
sk_ | otp:dashboard:read | otp:read, * |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
issueId | path | string (uuid) | yes | issueId returned by POST /v1/issue. |
Response (200)
The issue projection.
| Field | Type | Required | Description |
|---|---|---|---|
issueId | string (uuid) | yes | |
purpose | string | yes | |
templateId | string | yes | |
channel | "alimtalk" | "sms" | yes | |
verificationStatus | "expired" | "issued" | "max_attempts" | "replaced" | "verified" | yes | Effective status: an issued row past its expiry is reported as expired. |
deliveryStatus | "delivered" | "failed" | "queued" | "sent" | "unknown" | yes | Latest tracked delivery status; unknown when the tracker has no record or is unavailable. |
overallStatus | "delivered" | "delivery_failed" | "expired" | "in_progress" | "max_attempts" | "pending_lookup" | "replaced" | "verified" | yes | Same derivation as GET /v1/status. |
billingStatus | "debit_pending" | "debited" | "release_pending" | "released" | "reserved" | yes | Billing lifecycle of an issue: credit is reserved at admission, then either debited (debit_pending -> debited) or released (release_pending -> released) once send processing finishes. |
debitedAmount | integer | yes | Credits debited for this issue so far. |
currency | string | yes | Credit unit, currently CREDIT. |
expiresAt | string (date-time) | Undefined only for legacy records that predate persisted expiry timestamps. | |
verifiedAt | string (date-time) | Present once the issue was verified. | |
attemptsUsed | integer | yes | |
maxAttempts | integer | yes | |
attemptsRemaining | integer | yes | |
createdAt | string (date-time) | yes | |
updatedAt | string (date-time) | yes |
Error responses
Every error uses the { defined, code, status, message, data? } envelope. See Errors.
| Status | code | Description |
|---|---|---|
| 400 | BAD_REQUEST | issueId is not a UUID. |
| 401 | UNAUTHORIZED | the Authorization: Bearer credential is missing, malformed, inactive, or rejected by introspection. |
| 403 | FORBIDDEN | the credential lacks otp:dashboard:read (or an accepted alias), or a pk_ public key was used. Public keys are limited to issue/verify. |
| 404 | NOT_FOUND | no issue with this issueId exists for the authenticated app. |
| 409 | CONFLICT | the request conflicts with the current state of the resource. |
| 500 | INTERNAL_SERVER_ERROR | unexpected server failure. Undefined errors (defined: false) use the same envelope. |
| 503 | SERVICE_UNAVAILABLE | credential introspection or a downstream dependency is temporarily unavailable. Retry with backoff. |
Example request
curl "https://api.k-otp.dev/v1/issues/0192f3c4-8b7a-7c3e-9a51-2f4d6e8b1a90" \
-H "Authorization: Bearer $KOTP_SECRET_KEY"