{"openapi":"3.0.0","paths":{"/v1/public/balance":{"get":{"operationId":"PublicApiController_getBalance","summary":"Get current balance","description":"Returns the current balance for the authenticated user. API key authentication only.","parameters":[],"responses":{"200":{"description":"Balance retrieved successfully.","content":{"application/json":{"example":{"balance":10000}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API"],"security":[{"ApiKey":[]}]}},"/v1/public/balance/history":{"get":{"operationId":"PublicApiController_getBalanceHistory","summary":"Get balance mutation history","description":"Returns paginated balance mutation log with totals. API key authentication only.","parameters":[{"name":"startDate","required":false,"in":"query","description":"Filter by createdAt >= startDate (ISO 8601, e.g. 2026-01-15T00:00:00Z).","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Filter by createdAt <= endDate (ISO 8601, e.g. 2026-01-15T23:59:59Z).","schema":{"type":"string"}},{"name":"type","required":false,"in":"query","description":"Filter by mutation direction. 0 = addition (credit, e.g. deposit/refund), 1 = deduction (debit, e.g. order). Omit for both.","schema":{"enum":[0,1],"type":"number"}},{"name":"category","required":false,"in":"query","description":"Filter by mutation category. Common values: DEPOSIT, ORDER, REFUND, CLAIM_VOUCHER, ADJUSTMENT. Omit for all.","schema":{"type":"string"}},{"name":"pageSize","required":false,"in":"query","description":"Items per page. Defaults to 10.","example":10,"schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (1-based). Defaults to 1.","example":1,"schema":{"type":"number"}}],"responses":{"200":{"description":"Balance history retrieved successfully. `category` is numeric: 0 ORDER, 1 CANCEL_ORDER, 2 REFUND_ORDER, 3 REACTIVATE_ORDER, 4 DEPOSIT, 5 REVOKE_DEPOSIT, 6 CLAIM_VOUCHER, 7 TRANSFER_BALANCE, 8 WITHDRAW, 9 REFUND_DEPOSIT, 10 REQUEST_BALANCE.","content":{"application/json":{"example":{"data":[{"id":"9438de94-3887-43e0-8153-b5c8ecfb099b","type":0,"category":4,"amount":10000,"currentBalance":10000,"invoiceNo":"SMSVirtual-DEP-1779273864974","createdAt":"2026-05-20T10:45:07.406Z"},{"id":"28e3c5b5-d1e3-4b3c-9d96-b49697df9bae","type":1,"category":0,"amount":821,"currentBalance":9179,"invoiceNo":"SMSVirtual-ORD-17792743369091","createdAt":"2026-05-20T10:52:17.306Z"}],"count":7,"totalAddition":12941,"totalDeduction":2941}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API"],"security":[{"ApiKey":[]}]}},"/v1/public/profile":{"get":{"operationId":"PublicApiController_getProfile","summary":"Get user profile","description":"Returns the authenticated user profile. API key authentication only.","parameters":[],"responses":{"200":{"description":"Profile retrieved successfully.","content":{"application/json":{"example":{"id":"c0a0925c-0629-4119-88a8-50bfd02d4398","email":"partner@example.com","name":"Jane Doe","phoneNumber":"5551234567","defaultCountryId":"e0716e8c-e83d-4400-8ebd-16aea6536e41","countryName":"Country A","status":1,"createdAt":"2026-05-20T10:42:55.799Z"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API"],"security":[{"ApiKey":[]}]}},"/v1/public/orders/history":{"get":{"operationId":"PublicOrdersController_history","summary":"Get order history (envelope level)","description":"Returns paginated order history at the Order envelope level. Each row is a purchase that may contain one or more activations.","parameters":[{"name":"startDate","required":false,"in":"query","description":"Filter by createdAt >= startDate (ISO 8601, e.g. 2026-01-15T00:00:00Z).","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Filter by createdAt <= endDate (ISO 8601, e.g. 2026-01-15T23:59:59Z).","schema":{"type":"string"}},{"name":"search","required":false,"in":"query","description":"Case-insensitive substring match on invoice number, phone number, or service name.","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by order status. 0 = PENDING, 1 = SUCCESS, 2 = FAILED, 3 = REFUNDED, 4 = EXPIRED. Omit for all.","schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","description":"Items per page. Defaults to 10.","example":10,"schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (1-based). Defaults to 1.","example":1,"schema":{"type":"number"}}],"responses":{"200":{"description":"Order history retrieved successfully. `status` (envelope, statusOrder): 0 PENDING, 1 SUCCESS, 2 FAILED, 3 REFUNDED, 4 EXPIRED. `type` (typeOrder): 0 SINGLESERVICE, 1 MULTISERVICE.","content":{"application/json":{"example":{"data":[{"id":"1272a1eb-ad4a-47ed-bb43-d03f7b61479d","amount":821,"quantity":1,"status":4,"type":0,"transactionId":"4d725d41-41cf-4e4b-a2c3-baaf9677f0d3","createdAt":"2026-05-20T10:52:17.306Z","updatedAt":"2026-05-21T07:51:41.664Z","orderDetail":[{"id":"caf471a1-858c-4015-8735-ba1743aaa528","activationId":"399446561","orderId":"1272a1eb-ad4a-47ed-bb43-d03f7b61479d","serviceCountryId":"0de78b36-76e9-4012-a3ec-eac5649610f1","servicePrice":821,"operatorId":null,"phoneNumber":"5551234567","activationTime":"2026-05-20T13:52:17.000Z","expiredTime":"2026-05-20T11:12:17.306Z","otpRequestedCount":1,"otpUsedCount":0,"status":7,"isReactivateAllowed":true,"createdAt":"2026-05-20T10:52:17.306Z","updatedAt":"2026-05-21T07:51:41.664Z","serviceCountry":{"id":"0de78b36-76e9-4012-a3ec-eac5649610f1","serviceId":"0a7d6956-abe6-451f-8107-997014ebae07","countryId":"f7c8e084-8e0c-4661-8d02-14829c97d960","retailActualPriceProvider":0.01,"retailSellPrice":980,"totalStock":85253,"isActive":true,"createdAt":"2025-12-04T08:57:19.050Z","updatedAt":"2026-05-21T13:40:03.440Z","service":{"id":"0a7d6956-abe6-451f-8107-997014ebae07","name":"Example Service A","code":"svc-a","imageUrl":"https://cdn.example.com/icons/svc-a.png","stock":1717394,"isActive":true,"minPrice":920.6,"maxPrice":234854,"categoryId":"685e2c2f-6318-45be-8dc8-9c1b65737feb","parentServiceId":null,"discount":0,"createdAt":"2025-12-04T08:30:17.244Z","updatedAt":"2026-05-21T13:40:03.440Z"},"country":{"id":"f7c8e084-8e0c-4661-8d02-14829c97d960","code":"6","name":"Country A","imageUrl":"https://cdn.example.com/flags/ca.png","isActive":true,"createdAt":"2025-12-04T08:30:11.022Z","updatedAt":"2026-04-06T07:16:01.730Z"}}}],"transaction":{"id":"4d725d41-41cf-4e4b-a2c3-baaf9677f0d3","type":"ORDER","invoiceNo":"SMSVirtual-ORD-17792743369091","amount":821,"serviceFee":0,"additionalFee":0,"totalAmount":821,"status":3,"createdAt":"2026-05-20T10:52:17.306Z","updatedAt":"2026-05-21T07:51:41.664Z"}}],"total":42,"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Orders"],"security":[{"ApiKey":[]}]}},"/v1/public/orders/history-activation":{"get":{"operationId":"PublicOrdersController_historyActivation","summary":"Get activation history (individual numbers)","description":"Returns paginated activation history at the OrderDetail level. Each row is a single number/activation. Includes OTP receipts when they exist.","parameters":[{"name":"startDate","required":false,"in":"query","description":"Filter by createdAt >= startDate (ISO 8601).","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Filter by createdAt <= endDate (ISO 8601).","schema":{"type":"string"}},{"name":"search","required":false,"in":"query","description":"Case-insensitive substring match on phone number, service name, or country.","schema":{"type":"string"}},{"name":"pageSize","required":false,"in":"query","description":"Items per page. Defaults to 10.","example":10,"schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (1-based). Defaults to 1.","example":1,"schema":{"type":"number"}}],"responses":{"200":{"description":"Activation history retrieved successfully. `status` (statusActivation): 0 PENDING, 1 READY, 2 RESEND, 3 SUCCESS, 4 COMPLETED, 5 CANCELLED, 6 EXPIRED, 7 REFUNDED, 8 CANCELLED_BUT_WAITING_CONFIRM. `phoneNumber` is digits-only with country-code prefix (no leading `+`).","content":{"application/json":{"example":{"data":[{"id":"14c3ee79-7fe1-4114-91d1-ffbdb012bd61","activationId":"399427964","orderId":"3fc6610b-f7fd-4cab-b81a-45668d57094f","serviceCountryId":"b2bd2448-3266-4a6f-a154-fb83852d1e8b","servicePrice":1060,"operatorId":null,"phoneNumber":"5551234567","activationTime":"2026-05-20T13:46:06.000Z","expiredTime":"2026-05-20T11:06:06.833Z","otpRequestedCount":1,"otpUsedCount":0,"status":5,"isReactivateAllowed":false,"createdAt":"2026-05-20T10:46:06.833Z","updatedAt":"2026-05-20T10:51:23.507Z","orderDetailOtp":[],"operator":null,"serviceCountry":{"id":"b2bd2448-3266-4a6f-a154-fb83852d1e8b","serviceId":"73829239-0f1e-4ba4-aa0f-76378c01ac04","countryId":"f7c8e084-8e0c-4661-8d02-14829c97d960","retailActualPriceProvider":0.05,"retailSellPrice":1700,"totalStock":40673,"isActive":true,"createdAt":"2025-12-04T08:57:19.050Z","updatedAt":"2026-05-21T13:40:03.440Z","service":{"id":"73829239-0f1e-4ba4-aa0f-76378c01ac04","name":"Example Service A","code":"svc-a","imageUrl":"https://cdn.example.com/icons/svc-a.png","stock":40673,"isActive":true,"minPrice":780.5,"maxPrice":9695.6,"categoryId":"e6393242-63d3-4485-bb41-92a396bf8f25","parentServiceId":null,"discount":0,"createdAt":"2025-12-04T08:30:17.256Z","updatedAt":"2026-05-21T13:40:03.440Z"},"country":{"id":"f7c8e084-8e0c-4661-8d02-14829c97d960","code":"6","name":"Country A","imageUrl":"https://cdn.example.com/flags/ca.png","isActive":true,"createdAt":"2025-12-04T08:30:11.022Z","updatedAt":"2026-04-06T07:16:01.730Z"}},"order":{"id":"3fc6610b-f7fd-4cab-b81a-45668d57094f","amount":1060,"quantity":1,"status":3,"type":0,"transactionId":"55677883-5b1c-4889-b861-e9eb5356f302","createdAt":"2026-05-20T10:46:06.833Z","updatedAt":"2026-05-20T10:51:23.507Z","transaction":{"id":"55677883-5b1c-4889-b861-e9eb5356f302","type":"ORDER","invoiceNo":"SMSVirtual-ORD-17792739663621","amount":1060,"serviceFee":0,"additionalFee":0,"totalAmount":1060,"status":3,"createdAt":"2026-05-20T10:46:06.833Z","updatedAt":"2026-05-20T10:51:23.507Z"}},"service":{"id":"73829239-0f1e-4ba4-aa0f-76378c01ac04","name":"Example Service A","code":"svc-a","imageUrl":"https://cdn.example.com/icons/svc-a.png","stock":40673,"isActive":true,"minPrice":781,"maxPrice":9696,"categoryId":"e6393242-63d3-4485-bb41-92a396bf8f25","parentServiceId":null,"discount":0,"createdAt":"2025-12-04T08:30:17.256Z","updatedAt":"2026-05-21T13:40:03.440Z"}}],"total":1,"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Orders"],"security":[{"ApiKey":[]}]}},"/v1/public/orders/ongoing-activation":{"get":{"operationId":"PublicOrdersController_ongoingActivation","summary":"Get ongoing activations","description":"Returns paginated activations that are still in-flight (PENDING / READY). Use this to poll for the OTP.","parameters":[{"name":"search","required":false,"in":"query","description":"Case-insensitive substring match on phone number, service name, or country.","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by activation status. 0 = PENDING, 1 = READY, 2 = RESEND. Omit to include all in-flight states.","schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","description":"Items per page. Defaults to 10.","example":10,"schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (1-based). Defaults to 1.","example":1,"schema":{"type":"number"}}],"responses":{"200":{"description":"Ongoing activations retrieved. Same row shape as `/orders/history-activation` (with `serviceCountry`/`order`/`service` nesting). `data: []` is the common case when nothing is in-flight.","content":{"application/json":{"example":{"data":[],"total":0,"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Orders"],"security":[{"ApiKey":[]}]}},"/v1/public/orders/request-single-service":{"post":{"operationId":"PublicOrdersController_requestSingleService","summary":"Create a new order (single service)","description":"Creates a new activation order for a single service.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderSingleServiceDto"}}}},"responses":{"201":{"description":"Order created successfully.","content":{"application/json":{"example":{"data":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","invoiceNo":"INV-20260115-042","status":0,"totalPrice":5000,"orderDetail":[{"id":"f1e2d3c4-b5a6-7890-abcd-ef1234567890","phoneNumber":"+12025550987","status":0,"price":5000,"service":{"name":"Example Service","code":"svc"},"country":{"name":"Country A","code":"CA"}}]},"statusCode":201,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Orders"],"security":[{"ApiKey":[]}]}},"/v1/public/orders/getStatus/{id}":{"get":{"operationId":"PublicOrdersController_getStatus","summary":"Get activation status + OTP","description":"Returns the current activation status and any received OTP codes.","parameters":[{"name":"id","required":true,"in":"path","description":"Order detail (activation) UUID. From the `id` field of items in `GET /v1/public/orders/history-activation` or `GET /v1/public/orders/ongoing-activation`.","example":"f1e2d3c4-b5a6-7890-abcd-ef1234567890","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Activation status retrieved.","content":{"application/json":{"example":{"data":{"id":"f1e2d3c4-b5a6-7890-abcd-ef1234567890","phoneNumber":"+12025550123","status":3,"service":{"name":"Example Service","code":"svc"},"country":{"name":"Country A","code":"CA"},"orderDetailOtp":[{"id":"a1b2c3d4-0000-0000-0000-000000000001","otpCode":"482917","receivedAt":"2026-01-15T10:31:15.000Z"}]},"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Orders"],"security":[{"ApiKey":[]}]}},"/v1/public/orders/ready/{id}":{"put":{"operationId":"PublicOrdersController_readyActivation","summary":"Mark activation as ready","description":"Tells the provider that the rented number has successfully been used to start a registration. Idempotent.","parameters":[{"name":"id","required":true,"in":"path","description":"Order detail (activation) UUID.","example":"f1e2d3c4-b5a6-7890-abcd-ef1234567890","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Activation marked as ready.","content":{"application/json":{"example":{"data":{"id":"f1e2d3c4-b5a6-7890-abcd-ef1234567890","status":1,"message":"Activation is now READY"},"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Orders"],"security":[{"ApiKey":[]}]}},"/v1/public/orders/resend/{id}":{"put":{"operationId":"PublicOrdersController_resendActivation","summary":"Resend OTP","description":"Requests another OTP attempt on the same number without releasing it.","parameters":[{"name":"id","required":true,"in":"path","description":"Order detail (activation) UUID.","example":"f1e2d3c4-b5a6-7890-abcd-ef1234567890","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Resend request accepted.","content":{"application/json":{"example":{"data":{"id":"f1e2d3c4-b5a6-7890-abcd-ef1234567890","status":2,"message":"Resend requested"},"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Orders"],"security":[{"ApiKey":[]}]}},"/v1/public/orders/cancel/{id}":{"put":{"operationId":"PublicOrdersController_cancelActivation","summary":"Cancel an activation","description":"Releases the rented number back to the pool and refunds the cost. Only succeeds while the activation is still PENDING and no OTP has been received.","parameters":[{"name":"id","required":true,"in":"path","description":"Order detail (activation) UUID.","example":"f1e2d3c4-b5a6-7890-abcd-ef1234567890","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Activation cancelled and refunded.","content":{"application/json":{"example":{"data":true,"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Orders"],"security":[{"ApiKey":[]}]}},"/v1/public/orders/complete/{id}":{"put":{"operationId":"PublicOrdersController_completeActivation","summary":"Complete an activation","description":"Marks the activation as done. Call after you have received and used the OTP successfully.","parameters":[{"name":"id","required":true,"in":"path","description":"Order detail (activation) UUID.","example":"f1e2d3c4-b5a6-7890-abcd-ef1234567890","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Activation completed.","content":{"application/json":{"example":{"data":{"id":"f1e2d3c4-b5a6-7890-abcd-ef1234567890","status":4,"message":"Activation completed"},"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Orders"],"security":[{"ApiKey":[]}]}},"/v1/public/countries":{"get":{"operationId":"PublicCatalogController_getCountries","summary":"List countries","description":"Returns paginated list of available countries.","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based). Defaults to 1.","example":1,"schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","description":"Items per page. Defaults to 10.","example":10,"schema":{"type":"number"}},{"name":"search","required":false,"in":"query","description":"Case-insensitive substring match on country name or code.","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by status: \"1\" = active, \"0\" = inactive. Omit for all.","schema":{"type":"string"}}],"responses":{"200":{"description":"Countries retrieved successfully. `code` is the upstream-provider numeric ID, not ISO-3166. Use `id` (UUID) when calling other endpoints.","content":{"application/json":{"example":{"data":[{"id":"fffb7b69-833c-479e-ae7e-1d94e2e02ece","code":"74","name":"Country A","imageUrl":"https://cdn.example.com/flags/ca.png","isActive":true,"createdAt":"2025-12-04T08:30:11.360Z","updatedAt":"2025-12-04T08:30:11.360Z"},{"id":"c19f8312-8e1f-42d8-88d2-95c8ec37d820","code":"155","name":"Country B","imageUrl":"https://cdn.example.com/flags/cb.png","isActive":true,"createdAt":"2025-12-04T08:30:17.092Z","updatedAt":"2025-12-04T08:30:17.092Z"}],"count":206,"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Catalog"],"security":[{"ApiKey":[]}]}},"/v1/public/operators":{"get":{"operationId":"PublicCatalogController_getOperators","summary":"List operators","description":"Returns paginated list of mobile operators for a given country.","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based). Defaults to 1.","example":1,"schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","description":"Items per page. Defaults to 10.","example":10,"schema":{"type":"number"}},{"name":"countryId","required":false,"in":"query","description":"Country UUID returned by GET /v1/public/countries. Omit to list operators across all countries.","schema":{"type":"string"}}],"responses":{"200":{"description":"Operators retrieved successfully.","content":{"application/json":{"example":{"data":[{"id":"f7429050-edcb-42f0-8bef-e15997ae5d74","code":"op-a","name":"Operator A","countryId":"628bac14-7dd0-4ca8-8ea1-a58944e08bf7","createdAt":"2025-12-04T09:00:42.680Z","updatedAt":"2025-12-04T09:00:42.680Z"},{"id":"6b4d66ae-284f-410a-8da0-f84759360af4","code":"op-b","name":"Operator B","countryId":"628bac14-7dd0-4ca8-8ea1-a58944e08bf7","createdAt":"2025-12-04T09:00:42.680Z","updatedAt":"2025-12-04T09:00:42.680Z"}],"count":624,"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Catalog"],"security":[{"ApiKey":[]}]}},"/v1/public/services":{"get":{"operationId":"PublicCatalogController_getServices","summary":"List services","description":"Returns paginated list of available services (apps/platforms).","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based). Defaults to 1.","example":1,"schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","description":"Items per page. Defaults to 10.","example":10,"schema":{"type":"number"}},{"name":"search","required":false,"in":"query","description":"Case-insensitive substring match on service name or code.","schema":{"type":"string"}},{"name":"categoryId","required":false,"in":"query","description":"Filter by service category UUID. Omit for all categories.","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by status: \"1\" = active, \"0\" = inactive. Omit for all.","schema":{"type":"string"}},{"name":"sort","required":false,"in":"query","description":"Sort order. Options: price_asc (cheapest first), price_desc (most expensive first), stock_desc (highest stock first), name_asc, name_desc, discount_desc (default - highest discount first).","example":"price_asc","schema":{"enum":["price_asc","price_desc","stock_desc","name_asc","name_desc","discount_desc"],"type":"string"}}],"responses":{"200":{"description":"Services retrieved successfully. `minPrice`/`maxPrice` are the cheapest and most expensive sell price across all countries — useful for catalog UI but **not** what the user is charged. For per-country pricing call `GET /v1/public/services/list?countryId=…`.","content":{"application/json":{"example":{"data":[{"id":"bf1f5773-9674-40fe-a134-5cadaa66aa8d","name":"Example Service A","code":"svc-a","imageUrl":"https://cdn.example.com/icons/svc-a.png","stock":355921,"isActive":true,"minPrice":1304,"maxPrice":40358.6,"categoryId":"2e00d4f2-85e3-45d6-baeb-b33595c79a9e","parentServiceId":null,"discount":100,"createdAt":"2025-12-04T08:30:17.328Z","updatedAt":"2026-05-21T13:40:03.440Z","parent":null,"isPromo":true,"isAlias":false},{"id":"a4797eb5-6266-4196-a8b5-c120c8c43ecf","name":"Example Service B","code":"svc-b","imageUrl":"https://cdn.example.com/icons/svc-b.png","stock":58040,"isActive":true,"minPrice":1340,"maxPrice":33963.2,"categoryId":"2e00d4f2-85e3-45d6-baeb-b33595c79a9e","parentServiceId":null,"discount":100,"createdAt":"2025-12-04T08:30:17.320Z","updatedAt":"2026-05-21T13:40:03.440Z","parent":null,"isPromo":true,"isAlias":false}],"count":718,"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Catalog"],"security":[{"ApiKey":[]}]}},"/v1/public/services/list":{"get":{"operationId":"PublicCatalogController_getServicesByCountry","summary":"List services by country","description":"Returns services available in a specific country with pricing tiers. Each service includes a `prices[]` array with `serviceCountryPriceId` values that can be used to create orders.","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based). Defaults to 1.","example":1,"schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","description":"Items per page. Defaults to 10.","example":10,"schema":{"type":"number"}},{"name":"countryId","required":true,"in":"query","description":"Country UUID from GET /v1/public/countries. Required — pricing is country-specific.","schema":{"type":"string"}},{"name":"search","required":false,"in":"query","description":"Case-insensitive substring match on service name or code.","schema":{"type":"string"}},{"name":"categoryId","required":false,"in":"query","description":"Filter by service category UUID. Omit for all categories.","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by status: \"1\" = active, \"0\" = inactive. Omit for all.","schema":{"type":"string"}},{"name":"sort","required":false,"in":"query","description":"Sort order. Options: price_asc (cheapest first), price_desc (most expensive first), stock_desc (highest stock first), name_asc, name_desc, discount_desc (default - highest discount first).","example":"price_asc","schema":{"enum":["price_asc","price_desc","stock_desc","name_asc","name_desc","discount_desc"],"type":"string"}}],"responses":{"200":{"description":"Services with country-specific pricing retrieved. Use `data[].prices[].id` (the `serviceCountryPriceId`) when placing orders. `sellPrice` is the list price; `promoPrice` is the active promotion (apply when `isPromo: true`).","content":{"application/json":{"example":{"data":[{"id":"7c174d7e-c0f3-4e19-844c-7ca8f50b7326","name":"Example Service A","code":"svc-a","imageUrl":"https://cdn.example.com/icons/svc-a.png","stock":2207970,"isActive":true,"categoryId":"2e00d4f2-85e3-45d6-baeb-b33595c79a9e","parentServiceId":null,"discount":100,"createdAt":"2025-06-07T08:55:55.387Z","updatedAt":"2025-06-08T14:10:37.705Z","retailSellPrice":6100,"prices":[{"id":"a3093a46-2bad-428b-ac9f-2105940dc4d5","serviceCountryId":"f77e9012-aeb8-4a07-915a-72bab9100d2c","sellPrice":11000,"stock":126582,"createdAt":"2025-06-07T12:17:35.667Z","updatedAt":"2025-06-07T12:17:35.667Z","promoPrice":10000}],"isPromo":true}],"count":1,"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Catalog"],"security":[{"ApiKey":[]}]}},"/v1/public/deposits/rate":{"get":{"operationId":"PublicDepositsController_getDepositRate","summary":"Get deposit rate","description":"Returns the current deposit USD-to-coin rate, feature flag status, and minimum amounts. Use this for deposit UI display and USD conversion.","parameters":[],"responses":{"200":{"description":"Deposit rate retrieved successfully.","content":{"application/json":{"example":{"data":{"enabled":true,"baseCurrency":"USD","balanceCurrency":"COIN","coinPerUsd":17000,"minAmountUsd":1,"cryptoMinAmountUsd":7,"displayRate":"1 USD = 17.000 coin"},"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Deposits"],"security":[{"ApiKey":[]}]}},"/v1/public/deposits/history":{"get":{"operationId":"PublicDepositsController_history","summary":"Get deposit history","description":"Returns paginated deposit history with aggregate totals.","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based). Defaults to 1.","example":1,"schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","description":"Items per page. Defaults to 10.","example":10,"schema":{"type":"number"}},{"name":"startDate","required":false,"in":"query","description":"Filter by createdAt >= startDate (ISO 8601, e.g. 2026-01-15T00:00:00Z).","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Filter by createdAt <= endDate (ISO 8601, e.g. 2026-01-15T23:59:59Z).","schema":{"type":"string"}},{"name":"search","required":false,"in":"query","description":"Case-insensitive substring match on invoice number.","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","description":"Filter by deposit status. 0 = PENDING, 1 = SUCCESS, 2 = FAILED, 3 = EXPIRED, 4 = REFUNDED. Omit for all.","schema":{"type":"number"}},{"name":"depositMethodId","required":false,"in":"query","description":"Filter by deposit method UUID (from GET /v1/public/deposits). Omit for all methods.","schema":{"type":"string"}}],"responses":{"200":{"description":"Deposit history retrieved successfully. `total*Deposit` are sums of amounts; `totalPending`/`totalSuccess`/etc. are **counts** (wire format is string).","content":{"application/json":{"example":{"data":[{"id":"3e6a13a0-03ea-4673-bc9c-1ef5e3a89442","userId":"c0a0925c-0629-4119-88a8-50bfd02d4398","depositMethodId":"d9369da4-da43-4c44-a968-baef593bba8a","transactionId":"f40abbcb-5ca0-4401-8929-c414cbdf5079","amount":10000,"amountCoin":10000,"status":1,"paymentProofUrl":null,"paymentData":"00020101021226680016ID.PAKAIDONK.WWW…","expiredAt":"2026-05-21T18:44:25.000Z","createdAt":"2026-05-20T10:44:24.978Z","updatedAt":"2026-05-20T10:45:07.406Z","depositMethod":{"id":"d9369da4-da43-4c44-a968-baef593bba8a","paymentType":1,"processType":1,"name":"Bank Transfer","note":"-","rate":"1","imageUrl":"https://cdn.example.com/methods/bank-transfer.jpg","status":1,"minAmount":1000,"createdAt":"2025-12-04T08:24:23.670Z","updatedAt":"2026-05-07T09:29:47.473Z"},"transaction":{"id":"f40abbcb-5ca0-4401-8929-c414cbdf5079","type":"DEPOSIT","invoiceNo":"SMSVirtual-DEP-1779273864974","amount":10000,"serviceFee":575,"additionalFee":0,"totalAmount":10575,"status":1,"createdAt":"2026-05-20T10:44:24.978Z","updatedAt":"2026-05-20T10:45:07.406Z"}}],"total":6,"totalPendingDeposit":2000,"totalSuccessDeposit":10000,"totalCancelDeposit":8000,"totalRejectedDeposit":0,"totalRefundedDeposit":0,"totalPending":"1","totalSuccess":"1","totalCancel":"4","totalRejected":"0","totalRefunded":"0","statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Deposits"],"security":[{"ApiKey":[]}]}},"/v1/public/deposits/request":{"post":{"operationId":"PublicDepositsController_request","summary":"Create a deposit request","description":"Initiates a new deposit transaction. Send exactly one of `amount` (coin flow) or `amountUsd` (USD flow). For crypto methods, prefer `amountUsd`; backend validates the live NOWPayments minimum before creating the payment.","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDepositsDto"}}}},"responses":{"201":{"description":"Deposit request created successfully. `paymentData` carries the gateway reference (EMV QR string for QRIS, virtual-account number for bank transfer, crypto address for USDT/USDC). Render that, do not poll the deposit row.","content":{"application/json":{"example":{"data":{"id":"09b6781e-6134-43f4-953e-1c35033f3e66","userId":"c0a0925c-0629-4119-88a8-50bfd02d4398","depositMethodId":"c257b3fd-baa8-4974-8fab-9dcabb4acb86","transactionId":"f609afc0-5464-41ca-b31d-b49e5647db78","amount":119000,"amountCoin":119000,"requestedUsd":7,"depositUsdToCoinRate":17000,"depositPricingUnit":"USD","paymentCurrency":"USD","paymentAmount":7,"status":0,"paymentProofUrl":null,"paymentData":"0x19FcF4dcF10cE0388D592585a6A84e93D75825dF","expiredAt":"2026-05-22T17:21:57.000Z","createdAt":"2026-05-21T09:21:56.543Z","updatedAt":"2026-05-21T09:21:56.543Z"},"statusCode":201,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Deposits"],"security":[{"ApiKey":[]}]}},"/v1/public/deposits":{"get":{"operationId":"PublicDepositsController_getMethods","summary":"List deposit methods","description":"Returns available deposit methods (payment gateways). Use `note` as customer-facing guidance or tooltip copy. GooglePlay is excluded from the public API deposit method list.","parameters":[{"name":"page","required":false,"in":"query","description":"Page number (1-based). Defaults to 1.","example":1,"schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","description":"Items per page. Defaults to 10.","example":10,"schema":{"type":"number"}}],"responses":{"200":{"description":"Deposit methods retrieved successfully. `paymentType`: 1 = QRIS / e-wallet, 2 = crypto (USDT/USDC). `processType`: 1 = automated.","content":{"application/json":{"example":{"data":[{"id":"d9369da4-da43-4c44-a968-baef593bba8a","paymentType":1,"processType":1,"name":"QRIS","note":"QRIS can be paid with supported QRIS-compatible banking or e-wallet apps. Please scan the QR code from a compatible payment app.","rate":"1","imageUrl":"https://cdn.example.com/methods/qris.jpg","status":1,"minAmount":1000,"createdAt":"2025-12-04T08:24:23.670Z","updatedAt":"2026-05-07T09:29:47.473Z"},{"id":"c257b3fd-baa8-4974-8fab-9dcabb4acb86","paymentType":2,"processType":1,"name":"USDTBSC","note":"Send only USDT on BSC / BEP20 to this address. Transfers from other networks may be lost.","rate":"1","imageUrl":"https://cdn.example.com/methods/usdtbsc.jpg","status":1,"minAmount":255000,"createdAt":"2025-12-04T08:24:23.670Z","updatedAt":"2025-12-30T14:13:33.229Z"}],"count":4,"statusCode":200,"message":"success"}}}},"400":{"description":"Validation failed. The request body did not match the documented DTO schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"A referenced resource (id, code, …) does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Deposits"],"security":[{"ApiKey":[]}]}},"/v1/public/deposits/cancel/{id}":{"put":{"operationId":"PublicDepositsController_cancel","summary":"Cancel a pending deposit","description":"Cancels a deposit that is in PENDING status (status = 0). Returns an error if the deposit is already SUCCESS, FAILED, EXPIRED, or REFUNDED. If the deposit was already paid but not yet confirmed, the balance will be refunded.","parameters":[{"name":"id","required":true,"in":"path","description":"Deposit UUID from POST /v1/public/deposits/request","example":"3e6a13a0-03ea-4673-bc9c-1ef5e3a89442","schema":{"type":"string"}}],"responses":{"200":{"description":"Deposit cancelled successfully. Status changed to FAILED (2).","content":{"application/json":{"example":{"data":{"id":"3e6a13a0-03ea-4673-bc9c-1ef5e3a89442","userId":"c0a0925c-0629-4119-88a8-50bfd02d4398","depositMethodId":"d9369da4-da43-4c44-a968-baef593bba8a","transactionId":"f40abbcb-5ca0-4401-8929-c414cbdf5079","amount":10000,"amountCoin":10000,"status":2,"paymentProofUrl":null,"paymentData":"00020101021226680016ID.PAKAIDONK.WWW…","expiredAt":"2026-05-21T18:44:25.000Z","createdAt":"2026-05-20T10:44:24.978Z","updatedAt":"2026-05-22T05:30:00.000Z"},"statusCode":200,"message":"success"}}}},"400":{"description":"Deposit cannot be cancelled (already completed, failed, or expired).","content":{"application/json":{"example":{"statusCode":400,"message":"Deposit cannot be cancelled","error":"Bad Request"}}}},"401":{"description":"Authentication failed. Either no credentials were provided, the Bearer token is invalid/expired, or the `x-api-key` is unknown / soft-deleted / belongs to an inactive account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"403":{"description":"Authenticated but not permitted to perform this operation (e.g. role restriction, account not active).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}},"404":{"description":"Deposit not found or does not belong to the authenticated user.","content":{"application/json":{"example":{"statusCode":404,"message":"Deposit not found","error":"Not Found"}}}},"422":{"description":"Validation passed but the business rule blocks the operation. Common `error` codes: `NO_NUMBERS`, `BANNED`, `BAD_SERVICE`, `Insufficient balance`. See the per-endpoint description for the full list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorResponse"}}}}},"tags":["Public API - Deposits"],"security":[{"ApiKey":[]}]}}},"info":{"title":"'SMS Virtual' API Documentation","description":"OpenAPI specification for partner integrations with 'SMS Virtual'.\n\n## Authentication\n\nEvery endpoint outside of the catalog browse routes (`Countries`, `Operators`, `Services`) requires authentication. Two schemes are supported and either is accepted on the same endpoint:\n\n1. **Bearer token** — `Authorization: Bearer <jwt>`. Issued by `POST /v1/auth/login`. Used by the first-party FE/app and by partners who prefer short-lived credentials.\n2. **API Key** — `x-api-key: <user-api-key>`. Long-lived per-user key intended for server-to-server integrations. Manage from the dashboard.\n\nWhen both credentials are sent on the same request, the Bearer token takes precedence. Authenticate by clicking **Authorize** at the top right of this page.\n\n## Response envelope\n\nEvery successful response is wrapped in the same JSON envelope:\n\n```json\n{\n  \"data\":       // endpoint-specific payload\n  \"statusCode\": 200,\n  \"message\":    \"success\"\n}\n```\n\nList endpoints additionally include `count` (total matching records, ignoring page size). Some list endpoints add aggregate fields (e.g. `totalSuccessOrder`) — those are documented per-endpoint.\n\n## Error model\n\nErrors use the same shape across the API:\n\n```json\n{\n  \"statusCode\": 400,\n  \"error\":      \"Insufficient balance\",\n  \"message\":    \"Your balance is not enough to place this order.\"\n}\n```\n\nSwitch on `error` in client code — it is a stable, machine-readable code. `message` is human-readable and may change between releases. The standard status codes (400 / 401 / 403 / 404 / 422) appear under every authenticated endpoint; see the endpoint description for the full list of business `error` codes.\n\n## Pagination\n\nList endpoints accept `page` (1-based, default 1) and `pageSize` (default 10) query parameters. The response includes a `count` field with the total number of matching records.\n\n## End-to-end flow\n\nThe recommended onboarding flow for a partner integration:\n\n1. **Login.** `POST /v1/auth/login` with the registered email and password. The response carries `accessToken` (Bearer JWT) and `refreshToken`. Either authenticate subsequent requests with the JWT *or* copy the user's API key from the dashboard and send it as `x-api-key`.\n2. **Browse the catalog.**\n   - `GET /v1/countries` to list every supported country (each row carries the country `id`).\n   - `GET /v1/services` to list every service we can activate (each service has `minPrice` / `maxPrice` across all countries).\n   - `GET /v1/services/list?countryId=<id>` to list services *with prices* for a given country. Each `prices[]` row exposes a `serviceCountryPriceId` — that ID is what `POST /v1/orders/request-single-service` accepts.\n   - `GET /v1/services/{serviceId}/countries` powers the per-service country picker (with sort tabs: recommended / cheapest / best success / most stock).\n3. **Top up the balance** if needed.\n   - `GET /v1/deposits` lists the available deposit methods.\n   - `POST /v1/deposits/request` creates a deposit and returns the payment instructions.\n   - Poll `GET /v1/deposits/ongoing` (or wait for the deposit method-specific webhook) until the deposit moves to `SUCCESS`.\n4. **Place the order.**\n   - `POST /v1/orders/request-single-service` with `serviceCountryPriceId` (and optional `operatorId`, `quantity`, `autoSearchServer`).\n   - `POST /v1/orders/request-multi-service` if you want one phone number that can receive OTPs for several services.\n5. **Wait for the OTP.** Poll `GET /v1/orders/getStatus/{id}` (the `id` is the activation id returned by the order placement response) until the OTP is delivered. The same value is also pushed via your registered webhook if configured.\n6. **Resolve the order.**\n   - `PUT /v1/orders/complete/{id}` once the OTP has been used.\n   - `PUT /v1/orders/resend/{id}` to request another OTP attempt (allowed window depends on the provider).\n   - `PUT /v1/orders/cancel/{id}` if you no longer need the number — only succeeds *before* an OTP arrives.\n   - `POST /v1/orders/reactivate/{id}` to bring a number back from a recoverable error state.\n\n## Idempotency\n\nOrder placement and deposit request endpoints accept an optional `Idempotency-Key` header. Replays with the same key are de-duplicated server-side; treat 4xx responses as terminal and only retry on network errors / 5xx.\n\n## Status codes you will see in payloads\n\n`status` fields in responses are integer enums. Map them client-side using these legends:\n\n- **Order** (`statusOrder`): `0=PENDING, 1=SUCCESS, 2=EXPIRED, 3=CANCELLED, 4=REFUNDED, 5=CANCELLED_BUT_WAITING_CONFIRM`.\n- **Activation** (`statusActivation`): `0=PENDING, 1=READY, 2=RESEND, 3=SUCCESS, 4=COMPLETED, 5=CANCELLED, 6=EXPIRED, 7=REFUNDED, 8=CANCELLED_BUT_WAITING_CONFIRM`.\n- **Transaction** (`statusTransaction`): `0=PENDING, 1=SUCCESS, 2=FAILED, 3=REFUNDED, 4=EXPIRED`.\n- **Deposit** (`statusDeposit`): `0=PENDING, 1=SUCCESS, 2=FAILED, 3=EXPIRED, 4=REFUNDED`.","version":"1.0","contact":{"name":"'SMS Virtual' Support","url":"https://sms-virtual.net","email":"support@sms-virtual.net"}},"tags":[{"name":"Public API","description":"Account-level endpoints for partners: current balance, balance mutation history, and the authenticated user profile. Start here to confirm the API key works and to track spend per request."},{"name":"Public API - Deposits","description":"Top up the account balance before placing orders. List available payment methods, create a deposit request, and track its status. Order placement charges this balance atomically."},{"name":"Public API - Catalog","description":"Read-only catalog used to build the order request: pick a country, optionally narrow by operator, then look up the per-country price for the service you want via `/v1/public/services/list?countryId=…`."},{"name":"Public API - Orders","description":"Activation lifecycle: request a number, poll `getStatus/{id}` for the OTP, then `complete` (success), `resend` (need another code), or `cancel` (before the OTP arrives). History endpoints expose past activations."}],"servers":[{"url":"https://api.sms-virtual.net","description":"'SMS Virtual' (production)"},{"url":"http://localhost:3000","description":"'SMS Virtual' (local development)"}],"components":{"securitySchemes":{"ApiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"Per-user API key. Send as the `x-api-key` request header. When both Bearer token and API key are provided on the same request, the Bearer token takes precedence."}},"schemas":{"ApiErrorResponse":{"type":"object","properties":{"statusCode":{"type":"number","description":"HTTP status code mirroring the response status line.","example":400},"error":{"type":"string","description":"Short, machine-readable error code. Stable across releases — switch on this in client code rather than parsing the human-readable message."},"message":{"type":"string","description":"Human-readable explanation suitable for surfacing to end users."}},"required":["statusCode","error"]},"LoginDto":{"type":"object","properties":{"email":{"type":"string","description":"Account email address or username. Either form is accepted; partners typically register with their company email.","example":"partner@example.com"},"password":{"type":"string","description":"Account password.","example":"securePassword!","format":"password","minLength":6}},"required":["email","password"]},"CreateDepositsDto":{"type":"object","properties":{"depositMethodId":{"type":"string","description":"Deposit method `id` from `GET /v1/deposits` (list of available methods).","format":"uuid","example":"238189f7-a1b7-46a3-8b1a-46c6fed5a091"},"amount":{"type":"number","description":"Deposit amount in coins. Must be at least the `minAmount` declared by the chosen deposit method. Mutually exclusive with `amountUsd`.","example":100000,"minimum":1},"amountUsd":{"type":"number","description":"USD package amount for deposit. Backend computes credited coin using deposit_usd_to_coin_rate. Mutually exclusive with `amount`.","example":7,"minimum":1}},"required":["depositMethodId"]},"CreateOrderSingleServiceDto":{"type":"object","properties":{"serviceCountryPriceId":{"type":"string","description":"Identifier of the chosen service-country price tier. Obtain it from `GET /v1/services/list?countryId=…` (each `prices[]` row exposes a `serviceCountryPriceId`) or from `GET /v1/services/{serviceId}/countries`.","format":"uuid","example":"a3093a46-2bad-428b-ac9f-2105940dc4d5"},"operatorId":{"type":"string","description":"Optional operator constraint. Pass an `id` from `GET /v1/operators` to force a specific carrier; omit to let the system pick any operator.","format":"uuid","example":"0a23dc54-28af-4e15-bc09-5b73be22631d"},"quantity":{"type":"number","description":"How many activations to create on this order. Defaults to 1. Each activation consumes one number from the pool and is billed independently.","example":1,"minimum":1},"autoSearchServer":{"type":"boolean","description":"When the chosen price tier returns `NO_NUMBERS` / `SERVER_ERROR`, automatically retry against the next higher tier within the same service+country. Off by default to keep ordering deterministic.","example":false},"autoSearchOperator":{"type":"boolean","description":"When the selected operator returns `NO_NUMBERS`, retry without operator filter (let provider pick any available operator). Requires a specific operatorId to be set; ignored when operatorId is \"any\".","example":false}},"required":["serviceCountryPriceId"]},"CreateOrderMultipleServiceDto":{"type":"object","properties":{"serviceId":{"description":"IDs of the services that should share one phone number. The provider will assign a single number capable of receiving OTPs for every listed service.","example":["7c174d7e-c0f3-4e19-844c-7ca8f50b7326","f47934b4-7a2c-4bc6-9ae0-5c5c09690007"],"type":"array","items":{"type":"string","format":"uuid"}},"countryId":{"type":"string","description":"Country `id` from `GET /v1/countries`.","format":"uuid","example":"9f8a8ec7-6f4d-4bbe-bbce-1a873f7f0ef0"},"operatorId":{"type":"string","description":"Optional operator `id` from `GET /v1/operators`. Omit to let the system pick any operator.","format":"uuid","example":"0a23dc54-28af-4e15-bc09-5b73be22631d"}},"required":["serviceId","countryId"]},"ClaimVouchersDto":{"type":"object","properties":{"code":{"type":"string","description":"Voucher code printed on the promotion. Case-insensitive. Successful claims credit the user balance and create a `CLAIM_VOUCHER` row in balance history.","example":"XXXX-XGN837"}},"required":["code"]}}}}