قرارداد API درخواست OTP
این صفحه Context مصرف Endpoint را تکمیل میکند. Schema ماشینی و منبع حقیقت نهایی در backend/api/openapi/identity.yaml قرار دارد.
مشخصات
| فیلد | مقدار |
|---|---|
| عملیات | ساخت OTP Challenge |
| Method و Path | POST /api/v1/auth/otp/challenges |
| وضعیت | Beta |
| احراز هویت | ندارد |
| پاسخ موفق | 202 Accepted |
| Cache | no-store |
| Idempotency | الزامی |
Headerها
| Header | الزام | Rule |
|---|---|---|
Content-Type |
الزامی | application/json؛ Parameter معتبر مانند Charset پذیرفته میشود |
Idempotency-Key |
الزامی | رشته UTF-8 با طول 16 تا 128 و Entropy بالا |
X-Device-ID |
الزامی | UUID تصادفی و پایدار برای نصب App یا Browser |
X-Device-ID شناسه حساب یا Device Fingerprint مخفی نیست. Client آن را یکبار تصادفی میسازد، برای همان نصب پایدار نگه میدارد و بهعنوان Credential استفاده نمیکند.
Request
{
"mobile": "09121234567"
}
Object بسته است؛ Field ناشناخته، Body دوم، JSON نامعتبر یا Mobile خارج از طول ساختاری رد میشود. اعتبارسنجی واقعی قالب Mobile در Domain انجام میشود.
Response موفق
{
"challengeId": "0198b2ad-5687-7abc-8def-0123456789ab",
"maskedMobile": "0912****567",
"expiresAt": "2026-08-15T12:02:00Z",
"resendAvailableAt": "2026-08-15T12:01:00Z"
}
Header Location مسیر Canonical Challenge را برمیگرداند. پاسخ درباره وجود Account اطلاعاتی نمیدهد.
خطاها
| HTTP | Code | علت | Retry |
|---|---|---|---|
400 |
invalid_request |
Header، JSON یا Shape نامعتبر | پس از اصلاح Request |
409 |
idempotency_conflict |
استفاده Key برای Intent متفاوت | خیر؛ Key جدید برای Intent جدید |
415 |
unsupported_media_type |
Media Type غیر JSON | پس از اصلاح Header |
422 |
invalid_mobile |
شماره موبایل ایران نامعتبر | پس از اصلاح Mobile |
429 |
otp_rate_limited |
عبور از کنترل سوءاستفاده | پس از Retry-After |
503 |
otp_challenge_unavailable |
عدم پذیرش پایدار یا تحویل | Retry محدود با Backoff |
پاسخ خطا از application/problem+json، Code انگلیسی پایدار و requestId استفاده میکند. متن قابل نمایش باید با UX Writing محصول فارسی و امن باشد. پیادهسازی Bootstrap هنوز Detailهای انگلیسی دارد؛ این مورد پیش از اتصال UI یک Gap باز و نیازمند اصلاح همزمان OpenAPI، Test و Handler است.
Retry و شبکه ضعیف
- Retry همان Intent باید همان
Idempotency-Keyرا نگه دارد. - Timeout یا قطع پاسخ به معنی شکست قطعی نیست؛ Client ابتدا همان Request را با Key قبلی تکرار میکند.
4xxبهجز429خودکار Retry نمیشود.429ازRetry-Afterو503از Backoff نمایی محدود با Jitter پیروی میکند.
نمونه محلی
$headers = @{
"Idempotency-Key" = "local-otp-request-000001"
"X-Device-ID" = "0670e315-183a-4fd9-aa80-bf2f7b275063"
}
Invoke-RestMethod `
-Method Post `
-Uri "http://localhost:8080/api/v1/auth/otp/challenges" `
-ContentType "application/json" `
-Headers $headers `
-Body '{"mobile":"09121234567"}'