{"openapi":"3.1.0","info":{"title":"kiwiSMS API","version":"1.0.0","description":"REST API for SMS OTP number rental.\n\n## Quick start\n1. Create an API key in the dashboard (`/dashboard/api-keys`).\n2. `GET /api/v1/services` — list services with `kind`, `serviceNo`, and display `code` (e.g. `s1-5`).\n3. `POST /api/v1/rentals` with `{ \"kind\": \"s1\", \"serviceNo\": 5 }`.\n4. Poll `GET /api/v1/rentals/{id}` or configure webhooks for OTP delivery.\n\n## Service codes\nEach catalog row has `kind` (s1–s4, tm1), `serviceNo` (integer within kind), and `code` (`kind-serviceNo`, e.g. `s1-5`).\nLong-term plans use `kind` (l1–l3), `planNo`, and `code` (e.g. `l2-3`).\nUse `kind` + `serviceNo` / `planNo` when renting — not upstream provider codes.\n\n## Docs & spec\nHuman-readable: `/docs`. Machine-readable: `/openapi.json` or `/openapi.yaml`."},"servers":[{"url":"https://www.kiwisms.com","description":"Current deployment"}],"tags":[{"name":"Account","description":"Wallet balance"},{"name":"Catalog","description":"Services and pricing"},{"name":"Rentals","description":"Rent, poll, cancel, complete, renew"},{"name":"Long-term","description":"Long-term number plans and rentals"},{"name":"Webhooks","description":"Outbound OTP notifications to your server"}],"security":[{"ApiKeyHeader":[]},{"BearerAuth":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key format: `lsms_{prefix}_{secret}`"},"BearerAuth":{"type":"http","scheme":"bearer","description":"Same API key as Bearer token"}},"parameters":{"CountryQuery":{"name":"country","in":"query","description":"Numeric country code","schema":{"type":"string","enum":["187","16","36","43","78","48"],"default":"187"}},"CountryCodeQuery":{"name":"country_code","in":"query","description":"Alias for `country`","schema":{"type":"string","enum":["187","16","36","43","78","48"]}},"SyncQuery":{"name":"sync","in":"query","description":"Set to `0` to skip SMS sync (faster polling)","schema":{"type":"string","enum":["0","1"],"default":"1"}},"RentalId":{"name":"id","in":"path","required":true,"description":"KiwiSMS rental id (sequential integer)","schema":{"type":"integer","minimum":1}},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","description":"Optional UUID for safe retries on POST (max 256 chars, 24h TTL)","schema":{"type":"string","maxLength":256}},"PageQuery":{"name":"page","in":"query","description":"Page number (1-based)","schema":{"type":"integer","minimum":1,"default":1}},"PageSizeQuery":{"name":"pageSize","in":"query","description":"Items per page (max 100)","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},"SearchQuery":{"name":"q","in":"query","description":"Search by service name, code, kind, or service number","schema":{"type":"string"}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"code":{"type":"string"}}},"Balance":{"type":"object","required":["balance","currency"],"properties":{"balance":{"type":"number","description":"USD wallet balance"},"currency":{"type":"string","const":"USD"}}},"ServiceItem":{"type":"object","required":["kind","serviceNo","code","name","price","count","multiSms","durationMinutes"],"properties":{"kind":{"type":"string","enum":["s1","s2","s3","s4","tm1"]},"serviceNo":{"type":"integer","minimum":1,"description":"Service number within the kind (s1-1 → kind s1, serviceNo 1)"},"code":{"type":"string","description":"Display reference: `{kind}-{serviceNo}` (e.g. s1-5)","example":"s1-5"},"name":{"type":"string"},"price":{"type":"string","description":"USD price as string"},"count":{"type":"integer","description":"Available stock"},"multiSms":{"type":"boolean"},"durationMinutes":{"type":"integer","description":"Rental window in minutes for this service"}}},"ServicesResponse":{"type":"object","required":["countryCode","catalogMode","count","services"],"properties":{"countryCode":{"type":"string"},"catalogMode":{"type":"boolean"},"count":{"type":"integer"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServiceItem"}}}},"Rental":{"type":"object","required":["id","kind","serviceNo","phone","serviceName","status","price","codes","otpCode","expiresAt","createdAt","active","secondsRemaining"],"properties":{"id":{"type":"integer","description":"KiwiSMS rental id (sequential integer)"},"kind":{"type":"string","enum":["s1","s2","s3","s4","tm1"]},"serviceNo":{"type":["integer","null"],"description":"Catalog service number within kind"},"phone":{"type":"string"},"serviceName":{"type":"string"},"status":{"type":"string","enum":["WAITING","RECEIVED","COMPLETED","CANCELLED","EXPIRED"]},"price":{"type":"number"},"codes":{"type":"array","items":{"type":"string"}},"otpCode":{"type":["string","null"]},"expiresAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"active":{"type":"boolean"},"secondsRemaining":{"type":"integer"}}},"RentalCreated":{"type":"object","required":["id","kind","phone","serviceName","price","status","expiresAt"],"properties":{"id":{"type":"integer","description":"KiwiSMS rental id (sequential integer)"},"kind":{"type":"string","enum":["s1","s2","s3","s4","tm1"]},"phone":{"type":"string"},"serviceName":{"type":"string"},"price":{"type":"number"},"status":{"type":"string","const":"WAITING"},"expiresAt":{"type":"string","format":"date-time"},"asleep":{"type":"boolean"}}},"RentRequest":{"type":"object","required":["kind","serviceNo"],"properties":{"kind":{"type":"string","enum":["s1","s2","s3","s4","tm1"],"description":"Service kind (S.1–S.4, T-Mobile line)"},"serviceNo":{"type":"integer","minimum":1,"description":"Service number within the kind (from GET /api/v1/services)"},"max_price":{"oneOf":[{"type":"string"},{"type":"number"}],"description":"Maximum price willing to pay (USD)"},"areas":{"type":"string","description":"Comma-separated area codes"},"carrier":{"type":"string","enum":["tmo","vz","att"]},"country":{"type":"string","enum":["187","16","36","43","78","48"]},"country_code":{"type":"string","enum":["187","16","36","43","78","48"]},"phone":{"type":"string","minLength":10,"description":"K.2 only — reuse an existing phone (digits or E.164)"},"reuse_phone":{"type":"string","minLength":10,"description":"Alias for phone (K.2 reuse)"}}},"RentalListResponse":{"type":"object","required":["rentals","count"],"properties":{"rentals":{"type":"array","items":{"$ref":"#/components/schemas/Rental"}},"count":{"type":"integer"}}},"RentalResponse":{"type":"object","required":["rental"],"properties":{"rental":{"$ref":"#/components/schemas/Rental"}}},"RentResponse":{"type":"object","required":["rental"],"properties":{"rental":{"$ref":"#/components/schemas/RentalCreated"}}},"RentalActionResponse":{"type":"object","required":["success","rentalId","status"],"properties":{"success":{"type":"boolean","const":true},"rentalId":{"type":"string","description":"KiwiSMS rental id (numeric string)"},"status":{"type":"string","enum":["CANCELLED","COMPLETED"]}}},"PublicPricingItem":{"type":"object","required":["kind","serviceNo","code","name","price"],"properties":{"kind":{"type":"string","enum":["s1","s2","s3","s4","tm1"]},"serviceNo":{"type":"integer","minimum":1},"code":{"type":"string","example":"s1-5"},"name":{"type":"string"},"price":{"type":"string"}}},"PublicPricingResponse":{"type":"object","required":["verification"],"properties":{"verification":{"type":"array","items":{"$ref":"#/components/schemas/PublicPricingItem"}}}},"PublicServicesResponse":{"type":"object","required":["countryCode","services","total","page","pageSize","totalPages"],"properties":{"countryCode":{"type":"string"},"services":{"type":"array","items":{"$ref":"#/components/schemas/ServiceItem"}},"total":{"type":"integer"},"page":{"type":"integer","minimum":1},"pageSize":{"type":"integer","maximum":100},"totalPages":{"type":"integer","minimum":1},"q":{"type":"string","description":"Echo of search query when filtered"}}},"LongTermPlanItem":{"type":"object","required":["kind","planNo","code","serviceName","countryName","durationLabel","durationKey","price","renewPrice"],"properties":{"kind":{"type":"string","enum":["l1","l2","l3","ltm"]},"planNo":{"type":"integer","minimum":1},"code":{"type":"string","example":"l2-3"},"serviceName":{"type":"string"},"countryName":{"type":["string","null"]},"durationLabel":{"type":"string"},"durationKey":{"type":"string"},"price":{"type":"string"},"renewPrice":{"type":"string"}}},"LongTermPlansResponse":{"type":"object","required":["available","plans","total","page","pageSize","totalPages"],"properties":{"available":{"type":"boolean"},"count":{"type":"integer"},"plans":{"type":"array","items":{"$ref":"#/components/schemas/LongTermPlanItem"}},"total":{"type":"integer"},"page":{"type":"integer","minimum":1},"pageSize":{"type":"integer","maximum":100},"totalPages":{"type":"integer","minimum":1},"q":{"type":"string"}}},"LongTermRentRequest":{"type":"object","required":["kind","planNo"],"properties":{"kind":{"type":"string","enum":["l1","l2","l3","ltm"]},"planNo":{"type":"integer","minimum":1,"description":"Plan number within kind (from GET /api/v1/long-term/plans)"},"area_code":{"type":"string","description":"Optional US area code (L.1)"},"quantity":{"type":"integer","minimum":1,"description":"Bulk rent count (L.1 only; requires Idempotency-Key when > 1)"}}},"LongTermRental":{"type":"object","required":["id","kind","serviceName","phone","sellPrice","status"],"properties":{"id":{"type":"string","description":"Long-term rental id"},"kind":{"type":"string","enum":["l1","l2","l3","ltm"]},"planNo":{"type":["integer","null"]},"code":{"type":["string","null"],"example":"l2-3"},"serviceName":{"type":"string"},"phone":{"type":"string"},"sellPrice":{"type":"number"},"status":{"type":"string"},"activeFrom":{"type":["string","null"],"format":"date-time"},"activeTill":{"type":["string","null"],"format":"date-time"},"autoRenew":{"type":"boolean"},"active":{"type":"boolean"},"lineStatus":{"type":"string","enum":["active","sleep","expired"]}}},"LongTermRentalResponse":{"type":"object","required":["rental"],"properties":{"rental":{"$ref":"#/components/schemas/LongTermRental"}}},"LongTermRentalListResponse":{"type":"object","required":["rentals","count"],"properties":{"rentals":{"type":"array","items":{"$ref":"#/components/schemas/LongTermRental"}},"count":{"type":"integer"}}},"OtpWebhookPayload":{"type":"object","required":["event","rentalId","kind","serviceNo","code","serviceName","phone","otpCode","smsText","receivedAt"],"properties":{"event":{"type":"string","const":"sms.received"},"rentalId":{"type":"string","description":"KiwiSMS rental id (numeric string)"},"kind":{"type":"string","enum":["s1","s2","s3","s4","tm1"]},"serviceNo":{"type":["integer","null"]},"code":{"type":["string","null"],"description":"Display reference `{kind}-{serviceNo}` when known","example":"s1-5"},"serviceName":{"type":"string"},"phone":{"type":"string"},"otpCode":{"type":"string"},"smsText":{"type":"string"},"receivedAt":{"type":"string","format":"date-time"}},"description":"Outbound webhook POST (configure URL on account or API key). Signed with `X-Webhook-Signature` (HMAC-SHA256 hex of raw JSON body)."}},"responses":{"Unauthorized":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Account suspended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/api/v1/balance":{"get":{"operationId":"getBalance","tags":["Account"],"summary":"Wallet balance","responses":{"200":{"description":"USD balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Balance"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/services":{"get":{"operationId":"listServices","tags":["Catalog"],"summary":"Services with stock and prices","parameters":[{"$ref":"#/components/parameters/CountryQuery"},{"$ref":"#/components/parameters/CountryCodeQuery"}],"responses":{"200":{"description":"Service catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServicesResponse"}}}},"400":{"description":"Unsupported country","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Unsupported country code","code":"INVALID_COUNTRY"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"Service error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Failed to fetch services","code":"PROVIDER_ERROR"}}}}}}},"/api/v1/rentals":{"get":{"operationId":"listRentals","tags":["Rentals"],"summary":"List active rentals","parameters":[{"$ref":"#/components/parameters/SyncQuery"}],"responses":{"200":{"description":"Active rentals (WAITING / RECEIVED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"createRental","tags":["Rentals"],"summary":"Rent a number","description":"Charges wallet for a ~20 minute session. Send `Idempotency-Key` for safe retries.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentRequest"}}}},"responses":{"201":{"description":"Rental created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentResponse"}}}},"400":{"description":"Invalid JSON or validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Insufficient balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Insufficient balance","code":"INSUFFICIENT_BALANCE"}}}},"404":{"description":"Service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service unavailable","code":"SERVICE_UNAVAILABLE"}}}},"409":{"description":"Idempotency conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Idempotency key reused with different body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Idempotency-Key was already used with a different request body","code":"IDEMPOTENCY_KEY_REUSED"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/rentals/{id}":{"get":{"operationId":"getRental","tags":["Rentals"],"summary":"Poll rental status and OTP codes","parameters":[{"$ref":"#/components/parameters/RentalId"},{"$ref":"#/components/parameters/SyncQuery"}],"responses":{"200":{"description":"Rental details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Rental not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Rental not found","code":"RENTAL_NOT_FOUND"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/rentals/{id}/cancel":{"post":{"operationId":"cancelRental","tags":["Rentals"],"summary":"Cancel WAITING rental","description":"Refunds wallet when cancellation succeeds.","parameters":[{"$ref":"#/components/parameters/RentalId"}],"responses":{"200":{"description":"Cancelled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalActionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Not found or not cancellable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Rental not found or cannot be cancelled (only WAITING rentals)","code":"CANCEL_NOT_ALLOWED"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"Provider cancellation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Could not cancel rental. Try again shortly.","code":"PROVIDER_ERROR"}}}}}}},"/api/v1/rentals/{id}/done":{"post":{"operationId":"completeRental","tags":["Rentals"],"summary":"Mark rental completed","description":"Releases the number when you are finished.","parameters":[{"$ref":"#/components/parameters/RentalId"}],"responses":{"200":{"description":"Completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentalActionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Rental not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Rental not found","code":"RENTAL_NOT_FOUND"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/rentals/{id}/renew":{"post":{"operationId":"renewRental","tags":["Rentals"],"summary":"Renew same phone number","description":"Starts a new ~20 minute session for the same number. Supports `Idempotency-Key`.","parameters":[{"$ref":"#/components/parameters/RentalId"},{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"200":{"description":"Renewed (or idempotent replay)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentResponse"}}}},"201":{"description":"New rental session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Insufficient balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Insufficient balance","code":"INSUFFICIENT_BALANCE"}}}},"404":{"description":"Rental not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Rental not found","code":"NOT_FOUND"}}}},"409":{"description":"Idempotency conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Idempotency key reused with different body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/long-term/plans":{"get":{"operationId":"listLongTermPlans","tags":["Long-term"],"summary":"Long-term plans with prices","parameters":[{"$ref":"#/components/parameters/PageQuery"},{"$ref":"#/components/parameters/PageSizeQuery"},{"$ref":"#/components/parameters/SearchQuery"}],"responses":{"200":{"description":"Paginated long-term plan catalog","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LongTermPlansResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"Catalog fetch failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/long-term/rentals":{"get":{"operationId":"listLongTermRentals","tags":["Long-term"],"summary":"List long-term rentals","parameters":[{"$ref":"#/components/parameters/SyncQuery"}],"responses":{"200":{"description":"Long-term rentals","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LongTermRentalListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"createLongTermRental","tags":["Long-term"],"summary":"Rent a long-term number","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LongTermRentRequest"}}}},"responses":{"200":{"description":"Rental created (or idempotent replay)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LongTermRentalResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Insufficient balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Insufficient balance","code":"INSUFFICIENT_BALANCE"}}}},"404":{"description":"Plan not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Plan not found","code":"PLAN_NOT_FOUND"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/long-term/rentals/{id}":{"get":{"operationId":"getLongTermRental","tags":["Long-term"],"summary":"Poll one long-term rental","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/SyncQuery"}],"responses":{"200":{"description":"Long-term rental details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LongTermRentalResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Rental not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Rental not found","code":"RENTAL_NOT_FOUND"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/public/long-term-plans":{"get":{"operationId":"listPublicLongTermPlans","tags":["Long-term","Catalog"],"summary":"Paginated public long-term catalog (no auth)","security":[],"parameters":[{"$ref":"#/components/parameters/PageQuery"},{"$ref":"#/components/parameters/PageSizeQuery"},{"$ref":"#/components/parameters/SearchQuery"}],"responses":{"200":{"description":"Paginated long-term plans","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LongTermPlansResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"Catalog fetch failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/public/pricing":{"get":{"operationId":"getPublicPricing","tags":["Catalog"],"summary":"Public pricing snapshot (no auth)","security":[],"responses":{"200":{"description":"Top services for landing page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPricingResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/public/services":{"get":{"operationId":"listPublicServices","tags":["Catalog"],"summary":"Paginated public service catalog (no auth)","description":"Browse pricing without authentication. Supports search and pagination (max 100 per page).","security":[],"parameters":[{"$ref":"#/components/parameters/CountryQuery"},{"$ref":"#/components/parameters/PageQuery"},{"$ref":"#/components/parameters/PageSizeQuery"},{"$ref":"#/components/parameters/SearchQuery"}],"responses":{"200":{"description":"Paginated catalog page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicServicesResponse"}}}},"400":{"description":"Unsupported country","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"Catalog fetch failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"x-webhooks":{"smsReceived":{"post":{"tags":["Webhooks"],"summary":"OTP received (outbound to your URL)","description":"Configure webhook URL on your account or API key. When an OTP arrives, kiwiSMS POSTs JSON to your URL.\n\nVerify `X-Webhook-Signature`: HMAC-SHA256 hex digest of the **raw request body** using your webhook secret.\n\nRespond with HTTP 2xx to acknowledge. Non-2xx responses are logged but not retried automatically.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpWebhookPayload"},"example":{"event":"sms.received","rentalId":"1042","kind":"s1","serviceNo":5,"code":"s1-5","serviceName":"Google","phone":"+12025551234","otpCode":"123456","smsText":"Your Google verification code is 123456","receivedAt":"2026-05-29T12:00:00.000Z"}}}},"responses":{"2XX":{"description":"Your server acknowledged the webhook"}}}}}}