{"openapi":"3.0.0","paths":{"/v1/public/pricing/options":{"get":{"description":"Anonymous landing-page endpoint that returns customer-visible categories and calculator limits. It does not expose internal pricing rules.","operationId":"PricingController_getPublicCalculatorOptions_v1","parameters":[],"responses":{"200":{"description":"Public calculator configuration.","content":{"application/json":{"schema":{"example":{"currency":"USD","categories":[{"value":"authentication","label":"Authentication"},{"value":"utility","label":"Utility"},{"value":"marketing","label":"Marketing"}],"quantity":{"minimum":1,"maximum":1000000,"unit":"messages_per_month"},"internationalAuthentication":{"supported":true,"availability":"country_dependent"}}}}}}},"summary":"Get public calculator options","tags":["Pricing"]}},"/v1/public/pricing/countries":{"get":{"description":"Anonymous landing-page endpoint returning only the safe country selector fields used by the calculator.","operationId":"PricingController_listPublicCountries_v1","parameters":[],"responses":{"200":{"description":"Active customer-visible pricing countries.","content":{"application/json":{"schema":{"example":[{"countryIso2":"EG","countryName":"Egypt","phoneCode":"+20","marketName":"Egypt","internationalAuthenticationAvailable":true}]}}}}},"summary":"List countries supported by the public calculator","tags":["Pricing"]}},"/v1/public/pricing/calculate":{"get":{"description":"Anonymous landing-page calculator using the active standard Wevlix rate card. Quantity represents projected monthly messages and calculations include tier transitions. The response contains customer-facing totals only and never exposes Meta fees, markup, floors, caps, project overrides, or pricing-version identifiers.","operationId":"PricingController_calculatePublicPrice_v1","parameters":[{"name":"countryIso2","required":true,"in":"query","description":"Two-letter ISO 3166-1 country code.","schema":{"example":"EG","type":"string"}},{"name":"category","required":true,"in":"query","description":"WhatsApp message pricing category.","schema":{"example":"utility","type":"string","enum":["authentication","utility","marketing"]}},{"name":"quantity","required":true,"in":"query","description":"Projected messages for one calendar month. Tier transitions are included in the estimate.","schema":{"minimum":1,"maximum":1000000,"example":10000,"type":"number"}}],"responses":{"200":{"description":"Customer-visible standard pricing estimate.","content":{"application/json":{"schema":{"example":{"generatedAt":"2026-07-17T12:00:00.000Z","estimate":true,"currency":"USD","quantity":10000,"country":{"iso2":"EG","name":"Egypt","phoneCode":"+20"},"market":"Egypt","category":"utility","international":false,"estimatedAverageUnitPrice":"0.006800","estimatedTotal":"68.000000"}}}}}},"summary":"Calculate a public monthly messaging estimate","tags":["Pricing"]}},"/v1/public/pricing/telegram":{"get":{"description":"Anonymous provider-neutral estimate using the admin-selected direct or fallback Telegram provider, the active standard rate card, the global Other market, and quantity tiers. Provider identity and internal pricing details are never exposed.","operationId":"PricingController_calculatePublicTelegramPrice_v1","parameters":[{"name":"route","required":false,"in":"query","description":"Select direct Telegram OTP pricing or WhatsApp-to-Telegram fallback pricing.","schema":{"default":"direct","type":"string","enum":["direct","fallback"]}},{"name":"quantity","required":true,"in":"query","description":"Projected Telegram OTP messages. Quantity-tier transitions are included.","schema":{"minimum":1,"maximum":1000000,"example":100,"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"example":{"generatedAt":"2026-08-15T12:00:00.000Z","estimate":true,"currency":"USD","quantity":100,"estimatedAverageUnitPrice":"0.012000","estimatedTotal":"1.200000"}}}}}},"summary":"Calculate a public Telegram OTP estimate","tags":["Pricing"]}},"/v1/pricing/countries":{"get":{"description":"Returns the customer-visible country and market catalog used for quote and send requests. Use this to populate country selectors or validate countryIso2 values before sending OTPs.","operationId":"PricingController_listCountries_v1","parameters":[],"responses":{"200":{"description":"Countries and markets visible to customers.","content":{"application/json":{"schema":{"example":[{"countryIso2":"{ISO2_COUNTRY_CODE}","countryName":"Example Country","phoneCode":"+1","marketName":"Example Market","isActive":true}]}}}}},"summary":"List supported pricing countries","tags":["Pricing"]}},"/v1/projects/{projectId}/pricing/quote":{"get":{"description":"Calculates the estimated customer-visible price for one or more messages. Authentication international pricing is selected automatically from the connected WABA eligibility, primary business location, destination country, and effective date. This endpoint hides Meta costs, markup, floors, caps, and project-specific internal pricing rules.","operationId":"PricingController_quoteProject_v1","parameters":[{"name":"projectId","required":true,"in":"path","schema":{"type":"string"}},{"name":"countryIso2","required":false,"in":"query","schema":{"example":"{ISO2_COUNTRY_CODE}","type":"string"}},{"name":"countryName","required":false,"in":"query","schema":{"example":"Example Country","type":"string"}},{"name":"marketName","required":false,"in":"query","schema":{"example":"Example Market","type":"string"}},{"name":"category","required":false,"in":"query","schema":{"type":"string","enum":["authentication","marketing","utility","service","telegram_gateway_otp"]}},{"name":"quantity","required":false,"in":"query","schema":{"example":1000,"type":"number"}}],"responses":{"200":{"description":"A customer-visible pricing quote.","content":{"application/json":{"schema":{"example":{"projectId":"69f84309bc2b9b55a69bd508","pricingVersionId":"a1b2c3d4","currency":"USD","quantity":1,"country":{"iso2":"{ISO2_COUNTRY_CODE}","name":"Example Country","phoneCode":"+1"},"market":"Example Market","category":"AUTHENTICATION","international":false,"currentMonthlyDeliveredCount":120,"estimatedAverageUnitPrice":"0.250000","estimatedTotal":"0.25"}}}}}},"security":[{"bearer":[]}],"summary":"Calculate a project message price. Returns clean customer-visible totals only.","tags":["Pricing"]}},"/v1/api-key":{"get":{"description":"Validates the submitted project API key without requiring a functional scope. Returns only safe credential metadata and never returns the raw key, hash, encrypted value, or prefix.","operationId":"ApiKeyController_validate_v1","parameters":[],"responses":{"200":{"description":"The API key is active and valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyValidationResponseDto"},"example":{"keyId":"0c3e6e70-7c70-4da7-9f2b-7b7f0f25bb5f","name":"Production integration","projectId":"9d095bb0-c342-4a3c-8397-a09d646ccffd","type":"live","scopes":["otp:send","otp:status","otp:verify"],"expiresAt":null}}}},"401":{"description":"The API key is missing, invalid, expired, or revoked."}},"security":[{"api-key":[]}],"summary":"Validate an API key","tags":["API Key"]}},"/v1/public/status":{"get":{"description":"Use this endpoint from monitors or deployment smoke checks to verify the public API is reachable.","operationId":"PublicStatusController_status_v1","parameters":[],"responses":{"200":{"description":"The public API is healthy and reachable.","content":{"application/json":{"schema":{"example":{"service":"wevlix-public-api","status":"ok"}}}}}},"summary":"Check public API availability","tags":["System"]}},"/v1/public/assets/email-logo.png":{"get":{"operationId":"PublicAssetsController_emailLogo_v1","parameters":[],"responses":{"200":{"description":"The public Wevlix email logo."}},"summary":"Get the Wevlix email logo","tags":["System"]}},"/v1/otp/send":{"post":{"description":"Creates a WhatsApp OTP message request. Only to is required. If both otpMode and code are omitted, Wevlix generates the six-digit code. Supplying code without otpMode is valid and infers provided mode. In live mode, Wevlix selects an approved, sendable AUTHENTICATION template from the project WhatsApp account: it prefers the exact requested locale, then an eligible variant of the same language. If no matching language is available, the request is rejected before billing or queueing. Shared accounts also require project template access. Newly connected verified businesses with no existing templates normally receive the wevlix_otp_en and wevlix_otp_ar starters, but this endpoint does not guarantee either template name. Generated and provided modes use the same selected template. In sandbox mode or with a development key, delivery is simulated without an upstream call or billing. Use clientMessageId for retry-safe idempotency.","operationId":"OtpController_send_v1","parameters":[],"requestBody":{"required":true,"description":"Start with the minimal request. Add optional fields only when your integration needs them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendOtpDto"},"examples":{"minimalGenerated":{"summary":"1. Minimal generated OTP (recommended start)","value":{"to":"+12345678900"}},"explicitGenerated":{"summary":"2. Explicit generated mode","value":{"to":"+12345678900","otpMode":"generated"}},"inferredProvided":{"summary":"3. Supply your own code; provided mode is inferred","value":{"to":"+12345678900","code":"123456"}},"explicitProvided":{"summary":"4. Explicit provided mode","value":{"to":"+12345678900","otpMode":"provided","code":"123456"}},"retrySafeGenerated":{"summary":"5. Generated OTP with a retry-safe client identifier","value":{"to":"+12345678900","clientMessageId":"login_attempt_123456"}},"advanced":{"summary":"6. Advanced provided-code request","value":{"to":"+12345678900","code":"123456","clientMessageId":"login_attempt_123456","locale":"en","countryIso2":"US"}}}}}},"responses":{"200":{"description":"OTP request accepted. Live sends are queued for WhatsApp delivery; sandbox/development sends are queued for simulation.","content":{"application/json":{"examples":{"live":{"summary":"Live send","value":{"messageId":"0c3e6e70-7c70-4da7-9f2b-7b7f0f25bb5f","clientMessageId":"login_123456","otpMode":"generated","status":"queued","to":"+{country_code}{subscriber_number}","requestedTo":"+{country_code}{subscriber_number}","apiKeyType":"live","executionMode":"live","simulated":false,"pricing":{"currency":"USD","estimatedUnitPrice":"0.250000","estimatedTotal":"0.250000"}}},"sandbox":{"summary":"Sandbox or development-key send","value":{"messageId":"0c3e6e70-7c70-4da7-9f2b-7b7f0f25bb5f","clientMessageId":"login_123456","otpMode":"generated","status":"queued","to":"+{development_country_code}{development_subscriber_number}","requestedTo":"+{country_code}{subscriber_number}","apiKeyType":"development","executionMode":"sandbox","simulated":true,"pricing":{"currency":"USD","estimatedUnitPrice":"0.000000","estimatedTotal":"0.000000"},"sandbox":{"enabled":true,"reason":"development_key"}}}}}}},"400":{"description":"The payload is invalid. Common conflicts are otpMode=provided without code, otpMode=generated with code, or a code that is not exactly four or six digits."},"401":{"description":"Missing or invalid API key."},"403":{"description":"OTP sending is not allowed for this API key, the development-key phone allow-list, project WABA state, or project balance."}},"security":[{"api-key":[]}],"summary":"Create an OTP message request in live or sandbox execution mode","tags":["OTP Messages"]}},"/v1/otp/status/{messageId}":{"get":{"description":"Returns the latest lifecycle state for an OTP request. Use this endpoint to power customer support views, retry decisions, and verification UX.","operationId":"OtpController_status_v1","parameters":[{"name":"messageId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Current message status for the OTP request.","content":{"application/json":{"schema":{"example":{"messageId":"0c3e6e70-7c70-4da7-9f2b-7b7f0f25bb5f","clientMessageId":"login_123456","status":"delivered","otpMode":"generated","to":"+{country_code}{subscriber_number}","sentAt":"2026-06-18T08:00:00.000Z","deliveredAt":"2026-06-18T08:00:03.000Z","readAt":null,"failedAt":null,"billedAt":null,"verifiedAt":null,"chargedAmount":"0.25","recovery":null}}}}},"401":{"description":"Missing or invalid API key."},"403":{"description":"The API key does not allow OTP status reads."},"404":{"description":"The requested message was not found."}},"security":[{"api-key":[]}],"summary":"Read OTP message status, delivery, and verification progress","tags":["OTP Messages"]}},"/v1/otp/verify":{"post":{"description":"Checks a 4- to 8-digit code against the stored hash for a message. Generated and provided-code modes both use this verification endpoint.","operationId":"OtpController_verify_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyOtpDto"}}}},"responses":{"200":{"description":"The OTP code was accepted.","content":{"application/json":{"schema":{"example":{"verified":true,"messageId":"0c3e6e70-7c70-4da7-9f2b-7b7f0f25bb5f","clientMessageId":"login_123456","verifiedAt":"2026-06-18T08:01:00.000Z"}}}}},"400":{"description":"The OTP code or request is invalid."},"401":{"description":"Missing or invalid API key."},"403":{"description":"The API key does not allow OTP verification."}},"security":[{"api-key":[]}],"summary":"Verify an OTP code for a sent WhatsApp message","tags":["OTP Messages"]}},"/v1/telegram/otp/send":{"post":{"description":"The provider is selected by Wevlix administrators. The customer contract, API key scopes, simulation, rate limits, billing, status, and verification endpoints remain unchanged.","operationId":"TelegramOtpController_send_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendOtpDto"}}}},"responses":{"200":{"description":"Telegram OTP accepted for live delivery or sandbox simulation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendOtpResponseDto"}}}},"400":{"description":"The request payload is invalid."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Telegram OTP sending is disabled, disallowed by the key, or the project balance is insufficient."}},"security":[{"api-key":[]}],"summary":"Send an OTP through the configured Telegram provider","tags":["Telegram OTP Messages"]}},"/v1/sms/otp/send":{"post":{"description":"Wevlix selects the SMS gateway, sender, route, and price. Direct SMS remains controlled by Wevlix release gates.","operationId":"SmsOtpController_send_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendOtpDto"}}}},"responses":{"200":{"description":"SMS OTP accepted for live delivery or sandbox simulation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendOtpResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Send an OTP through the Wevlix-managed SMS provider","tags":["SMS OTP Messages"]}},"/v1/messages/logs":{"get":{"description":"Dashboard-style logical requests with recovery and fallback attempts, across all channels. The project is derived from the API key. History is limited to the last 30 days or the shorter project retention policy. Pagination and filters match the dashboard; grouping is always by request.","operationId":"MessagesController_listLogs_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":50,"type":"number"}},{"name":"direction","required":false,"in":"query","schema":{"type":"string","enum":["inbound","outbound"]}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["accepted","queued","sent","delivered","read","failed","billing_failed"]}},{"name":"executionMode","required":false,"in":"query","schema":{"type":"string","enum":["live","sandbox"]}},{"name":"recipientWaId","required":false,"in":"query","schema":{"type":"string"}},{"name":"clientMessageId","required":false,"in":"query","schema":{"type":"string"}},{"name":"from","required":false,"in":"query","schema":{"example":"2026-07-01T00:00:00.000Z","type":"string"}},{"name":"to","required":false,"in":"query","schema":{"example":"2026-07-31T23:59:59.999Z","type":"string"}},{"name":"search","required":false,"in":"query","description":"Search message id, client message id, WAM id, or recipient WhatsApp id.","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated customer-facing message requests and their delivery attempts."}},"security":[{"api-key":[]}],"summary":"List project message logs for the last 30 days","tags":["WhatsApp Messages"]}},"/v1/messages/template":{"post":{"description":"Supports authentication, utility, and marketing templates. Approved templates send normally. A template already submitted to Meta but still pending can remain queued while Wevlix performs bounded status refreshes for up to six minutes. Live keys send through Wevlix managed messaging and consume project balance. Development keys and sandbox projects simulate the same queued lifecycle without upstream delivery or balance charges.","operationId":"MessagesController_sendTemplate_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTemplateMessageDto"}}}},"responses":{"202":{"description":"Template message accepted and queued for delivery.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTemplateMessageResponseDto"}}}}},"security":[{"api-key":[]}],"summary":"Queue a WhatsApp template message","tags":["WhatsApp Messages"]}},"/v1/messages/text":{"post":{"description":"Sends a live free-text reply when the same recipient has sent this project a WhatsApp message within the previous 24 hours. The project is derived from the API key. Development keys and sandbox projects are rejected; use an approved template when the reply window is closed.","operationId":"MessagesController_sendText_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTextMessageDto"}}}},"responses":{"202":{"description":"Free-text reply accepted by the WhatsApp transport.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTextMessageResponseDto"}}}},"400":{"description":"The reply window is closed or unknown, or the key/project is not live."}},"security":[{"api-key":[]}],"summary":"Send a free-text WhatsApp reply","tags":["WhatsApp Messages"]}},"/v1/messages/{messageId}":{"get":{"description":"Returns delivery state and a recovery summary when Wevlix is waiting for Meta template approval or repairing sender and WhatsApp account readiness failures. Failures use stable Wevlix codes and never expose upstream provider details.","operationId":"MessagesController_getStatus_v1","parameters":[{"name":"messageId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Current template message status.","content":{"application/json":{"schema":{"example":{"messageId":"0c3e6e70-7c70-4da7-9f2b-7b7f0f25bb5f","clientMessageId":"order_confirmation_123","status":"queued","to":"+{country_code}{subscriber_number}","executionMode":"live","template":{"id":"9d095bb0-c342-4a3c-8397-a09d646ccffd","name":"order_confirmation","languageCode":"en_US","category":"UTILITY"},"sentAt":null,"deliveredAt":null,"readAt":null,"failedAt":null,"billedAt":null,"failureCode":null,"failureReason":null,"failureRetryable":null,"chargedAmount":null,"recovery":{"state":"waiting","reason":"template_pending","attempt":2,"deadlineAt":"2026-07-16T12:06:00.000Z","nextRetryAt":"2026-07-16T12:01:30.000Z"}}}}}}},"security":[{"api-key":[]}],"summary":"Read a template message delivery status","tags":["WhatsApp Messages"]}},"/v1/templates":{"get":{"description":"Paginated project templates using dashboard filters and statuses. Shared-WABA projects see only templates granted to them. Returns customer-facing template content without transport identifiers.","operationId":"TemplatesController_list_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":50,"type":"number"}},{"name":"search","required":false,"in":"query","schema":{"example":"otp","type":"string"}},{"name":"type","required":false,"in":"query","schema":{"type":"string","enum":["AUTHENTICATION","MARKETING","UTILITY","SERVICE"]}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["PENDING","APPROVED","REJECTED","PAUSED","DISABLED"]}},{"name":"approvalStatus","required":false,"in":"query","schema":{"type":"string","enum":["PENDING_ADMIN_REVIEW","APPROVED_AND_SUBMITTED","REJECTED_BY_ADMIN"]}},{"name":"language","required":false,"in":"query","schema":{"example":"en_US","type":"string"}},{"name":"wabaId","required":false,"in":"query","schema":{"example":"{meta_waba_id}","type":"string"}},{"name":"folderId","required":false,"in":"query","description":"Filter by folder id. Use \"unfiled\" for templates without a folder.","schema":{"type":"string"}}],"responses":{"200":{"description":"Templates, pagination, counts, and folders."}},"security":[{"api-key":[]}],"summary":"List templates available to the API key project","tags":["Template Messages"]},"post":{"description":"Requires a live project key. Creates a local draft for Wevlix review; does not bypass approval. For shared WABAs, submits a project-owned request only when the relevant category is enabled by admin.","operationId":"TemplatesController_create_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomTemplateDto"}}}},"responses":{"201":{"description":"Template draft pending Wevlix review."}},"security":[{"api-key":[]}],"summary":"Create a Utility or Marketing template draft","tags":["Template Messages"]}},"/v1/templates/requests":{"get":{"description":"Includes pending and rejected requests, scoped to the project from the API key.","operationId":"TemplatesController_requests_v1","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":50,"type":"number"}},{"name":"search","required":false,"in":"query","schema":{"example":"otp","type":"string"}},{"name":"type","required":false,"in":"query","schema":{"type":"string","enum":["AUTHENTICATION","MARKETING","UTILITY","SERVICE"]}},{"name":"status","required":false,"in":"query","schema":{"type":"string","enum":["PENDING","APPROVED","REJECTED","PAUSED","DISABLED"]}},{"name":"approvalStatus","required":false,"in":"query","schema":{"type":"string","enum":["PENDING_ADMIN_REVIEW","APPROVED_AND_SUBMITTED","REJECTED_BY_ADMIN"]}},{"name":"language","required":false,"in":"query","schema":{"example":"en_US","type":"string"}},{"name":"wabaId","required":false,"in":"query","schema":{"example":"{meta_waba_id}","type":"string"}},{"name":"folderId","required":false,"in":"query","description":"Filter by folder id. Use \"unfiled\" for templates without a folder.","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated project-owned template requests."}},"security":[{"api-key":[]}],"summary":"List this project’s shared-WABA template requests","tags":["Template Messages"]}},"/v1/templates/authentication":{"post":{"description":"Uses the existing OTP template builder and Wevlix review flow. Shared-WABA requests require admin-enabled authentication template creation. Requires a live project key.","operationId":"TemplatesController_createAuthentication_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDefaultAuthTemplateDto"}}}},"responses":{"201":{"description":"Authentication template draft pending review."}},"security":[{"api-key":[]}],"summary":"Create an authentication template request","tags":["Template Messages"]}},"/v1/templates/sync":{"post":{"description":"Requires a live project key. Synchronizes a project-owned WABA. Shared-WABA projects receive their centrally managed accessible catalog without triggering a platform-wide sync.","operationId":"TemplatesController_sync_v1","parameters":[],"responses":{"200":{"description":"Current sanitized template catalog."}},"security":[{"api-key":[]}],"summary":"Refresh project templates","tags":["Template Messages"]}},"/v1/templates/{templateId}":{"get":{"operationId":"TemplatesController_get_v1","parameters":[{"name":"templateId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Template content, approval, and readiness."}},"security":[{"api-key":[]}],"summary":"Get a project template or project-owned shared request","tags":["Template Messages"]},"patch":{"description":"Requires the complete custom-template body and a live project key. Submitted templates and authentication drafts cannot be edited. Serializes against admin approval.","operationId":"TemplatesController_update_v1","parameters":[{"name":"templateId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomTemplateDto"}}}},"responses":{"200":{"description":"Updated draft."}},"security":[{"api-key":[]}],"summary":"Replace a Utility or Marketing draft pending Wevlix review","tags":["Template Messages"]},"delete":{"description":"Requires a live project key. Submitted project-owned templates are deleted from Meta using the existing lifecycle. Shared platform templates cannot be deleted by project keys.","operationId":"TemplatesController_remove_v1","parameters":[{"name":"templateId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Template deletion result."}},"security":[{"api-key":[]}],"summary":"Delete an owned template or withdraw a pending shared request","tags":["Template Messages"]}},"/v1/templates/{templateId}/integration":{"get":{"description":"Uses the project from the API key, verifies that the approved template is available to that project, explains every send-time parameter in order, and returns sample JSON and cURL for POST /v1/messages/template. The project id is never accepted from the caller.","operationId":"TemplatesController_getIntegrationExample_v1","parameters":[{"name":"templateId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Template-specific parameter map and integration examples."}},"security":[{"api-key":[]}],"summary":"Generate a ready-to-copy integration request for a template","tags":["Template Messages"]}},"/v1/webhooks/outbound-status":{"get":{"operationId":"OutboundStatusWebhooksController_get_v1","parameters":[],"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"Get the project outbound message status webhook","tags":["Webhooks"]},"put":{"operationId":"OutboundStatusWebhooksController_update_v1","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateOutboundStatusWebhookDto"}}}},"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"Configure the project outbound message status webhook","tags":["Webhooks"]},"delete":{"operationId":"OutboundStatusWebhooksController_remove_v1","parameters":[],"responses":{"200":{"description":""}},"security":[{"api-key":[]}],"summary":"Delete the project outbound message status webhook","tags":["Webhooks"]}},"/v1/webhooks/outbound-status/test":{"post":{"operationId":"OutboundStatusWebhooksController_test_v1","parameters":[],"responses":{"201":{"description":""}},"security":[{"api-key":[]}],"summary":"Send a test outbound message status webhook","tags":["Webhooks"]}},"/v1/project":{"get":{"description":"Returns safe general information for the project belonging to the submitted API key. Another project cannot be selected.","operationId":"PublicProjectController_get_v1","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"example":{"id":"9d095bb0-c342-4a3c-8397-a09d646ccffd","name":"Example Project","slug":"example-project","active":true,"createdAt":"2026-09-09T12:00:00.000Z","updatedAt":"2026-09-09T12:00:00.000Z","balance":{"currency":"USD","settled":"20.0000","reserved":"2.0000","available":"18.0000"}}}}}}},"security":[{"api-key":[]}],"summary":"Get the API key project and its current balance","tags":["Project"]}},"/v1/auth/login":{"post":{"operationId":"setupLogin","tags":["Setup"],"summary":"Login to retrieve a dashboard access token","description":"Use this endpoint only from trusted first-party dashboard or setup tooling. The returned accessToken authorizes project setup calls such as listing project API keys. Do not use this token as the project API key for OTP requests.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email","example":"user@example.com"},"password":{"type":"string","format":"password","minLength":8,"example":"StrongPass123!"}}}}}},"responses":{"201":{"description":"Login succeeded. Use accessToken as Bearer token for setup endpoints.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string","example":"user_123"},"name":{"type":"string","example":"Jane Developer"},"email":{"type":"string","example":"user@example.com"}}},"accessToken":{"type":"string","example":"eyJhbGciOi..."},"refreshToken":{"type":"string","example":"wvlx_refresh_..."}}}}}}}},"401":{"description":"Email, password, verification, or account state failed."}}}},"/v1/projects/{projectId}/api-keys":{"get":{"operationId":"setupListProjectApiKeys","tags":["Setup"],"summary":"Get a project API key","description":"Returns production API keys for a project the signed-in user can manage. Choose the needed key by id or name, then use rawKey as X-API-Key for project API requests. Legacy hash-only keys may return rawKey as null until rotated in the dashboard.","security":[{"bearer":[]}],"parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Project id from the Wevlix dashboard."}],"responses":{"200":{"description":"Production API keys visible to the signed-in project member.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Default production key"},"type":{"type":"string","example":"live"},"rawKey":{"type":"string","nullable":true,"example":"wvlx_live_..."},"scopes":{"type":"array","items":{"type":"string"},"example":["otp:send","otp:status","otp:verify"]},"revokedAt":{"type":"string","nullable":true,"example":null},"expiresAt":{"type":"string","nullable":true,"example":null}}}}}}}}},"401":{"description":"Missing or invalid dashboard bearer token."},"403":{"description":"The signed-in user is not allowed to manage project API keys."}}}},"/v1/projects/{projectId}/whatsapp-account/templates":{"get":{"operationId":"setupListProjectWhatsappTemplates","tags":["Setup"],"summary":"List templates available to the project","description":"Returns the project template read model. Use the Wevlix template id from an APPROVED template when calling POST /v1/messages/template. This setup operation uses the dashboard Bearer token, not the project API key.","security":[{"bearer":[]}],"parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Project id from the Wevlix dashboard."},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by template name."},{"name":"type","in":"query","schema":{"type":"string","enum":["AUTHENTICATION","UTILITY","MARKETING","SERVICE"]}},{"name":"status","in":"query","schema":{"type":"string","enum":["PENDING","APPROVED","REJECTED","PAUSED","DISABLED"]}}],"responses":{"200":{"description":"Paginated templates with local ids, names, categories, languages, lifecycle state, and Meta approval status.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Wevlix template UUID. Use this value as templateId when sending."},"name":{"type":"string","example":"order_confirmation"},"languageCode":{"type":"string","example":"en_US"},"category":{"type":"string","example":"UTILITY"},"status":{"type":"string","example":"APPROVED"}}}},"page":{"type":"integer","example":1},"limit":{"type":"integer","example":50},"total":{"type":"integer","example":1}}},"example":{"items":[{"id":"9d095bb0-c342-4a3c-8397-a09d646ccffd","name":"order_confirmation","languageCode":"en_US","category":"UTILITY","status":"APPROVED"}],"page":1,"limit":50,"total":1}}}},"401":{"description":"Missing or invalid dashboard bearer token."},"403":{"description":"Project access is required."}}}}},"info":{"title":"Wevlix Messaging API","description":"Integrate production WhatsApp verification, notifications, and approved template messaging with one project-scoped API.\n\n## Start here\n\n1. [Create and configure a project](https://docs.wevlix.com/docs/public#quickstart).\n2. Keep the project API key in your backend or secret manager.\n3. Start in sandbox mode, send a request, and store the returned `messageId`.\n4. Read message status until it reaches a terminal state.\n5. Connect a WhatsApp Business Account, approve templates, fund the project, and switch to live mode.\n\n## Authentication\n\nMessaging endpoints use `X-API-Key`. Dashboard setup operations use a short-lived Bearer access token. These credentials are not interchangeable, and neither belongs in browser or mobile application code.\n\n## Sandbox and development keys\n\nSandbox projects and development keys execute the same validation, persistence, queue, status, and OTP verification flow without contacting the live messaging network or charging project balance. Development keys remain restricted to their configured test recipients.\n\n## Request lifecycle\n\nSend operations return a Wevlix `messageId`. Treat `accepted` and `queued` as asynchronous states. Continue with the matching status endpoint until `delivered`, `read`, or `failed`. Use a unique `clientMessageId` to make retries safe.\n\n## Response contract\n\nEvery JSON response uses the same envelope: `success`, either `data` or `error`, and `meta`. Preserve `meta.requestId` when contacting support.\n\nRead the [integration guide](https://docs.wevlix.com/docs/public) before using the API reference below.","version":"1.0","contact":{},"termsOfService":"https://wevlix.com/terms","x-logo":{"url":"/docs/public/assets/wevlix-logo.png","altText":"Wevlix"}},"tags":[{"name":"System","description":"Health and availability checks for public API consumers."},{"name":"Template Messages","description":"Manage project templates with templates:read/templates:write scopes, submit drafts for Wevlix review, and send approved authentication, utility, and marketing templates. Development keys are read-only for template management."},{"name":"OTP Messages","description":"Template-backed verification made simple. Start with only to, let Wevlix generate a six-digit code, or optionally provide your own four- or six-digit code. Live sends select an approved authentication template from the project WhatsApp account."},{"name":"Pricing","description":"Customer-visible country and quote endpoints for estimating message costs."},{"name":"Setup","description":"Optional dashboard-authenticated operations for retrieving a project API key before server-to-server integration."}],"servers":[{"url":"https://api.wevlix.com","description":"Primary API"}],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"Short-lived dashboard access token. Use only for the optional setup endpoints in this reference."},"api-key":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Project-scoped server credential used by messaging, status, OTP, and project pricing endpoints. Never expose it in browser or mobile code."}},"schemas":{"ApiKeyValidationResponseDto":{"type":"object","properties":{"keyId":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Production integration"},"projectId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["live","development"]},"scopes":{"type":"array","items":{"type":"string","enum":["project:read","project:balance:read","project:mode:read","project:analytics:read","billing:read","waba:read","templates:read","templates:write","otp:send","otp:status","otp:verify","messages:send","messages:read","contacts:read","contacts:write","contacts:delete","webhooks:read","webhooks:write","media:read","media:write"]}},"expiresAt":{"type":"string","format":"date-time","nullable":true}},"required":["keyId","name","projectId","type","scopes","expiresAt"]},"SendOtpDto":{"type":"object","properties":{"to":{"type":"string","example":"+{country_code}{subscriber_number}","description":"Recipient phone number in E.164 format: +{country_code}{subscriber_number}."},"countryIso2":{"type":"string","example":"{ISO2_COUNTRY_CODE}","description":"Optional validation hint. Wevlix derives the billing country from the E.164 recipient and rejects a mismatch."},"clientMessageId":{"type":"string","example":"login_123456"},"otpMode":{"type":"string","enum":["generated","provided"],"example":"generated","default":"generated","description":"Optional mode override. Omit it to let Wevlix generate the OTP, unless code is present, in which case provided mode is inferred. Use generated when Wevlix creates the OTP or provided when your backend supplies code."},"code":{"type":"string","example":"123456","description":"Optional four- or six-digit OTP supplied by your backend. Providing code without otpMode is valid and automatically selects provided mode. It is required when otpMode is provided and forbidden when otpMode is generated."},"locale":{"type":"string","example":"en"}},"required":["to"]},"VerifyOtpDto":{"type":"object","properties":{"messageId":{"type":"string","example":"0c3e6e70-7c70-4da7-9f2b-7b7f0f25bb5f"},"code":{"type":"string","example":"123456"},"clientMessageId":{"type":"string","example":"login_123456"}},"required":["messageId","code"]},"PricingEstimateDto":{"type":"object","properties":{"currency":{"type":"string","example":"USD"},"estimatedUnitPrice":{"type":"string","example":"0.250000"},"estimatedTotal":{"type":"string","example":"0.250000"}},"required":["currency","estimatedUnitPrice","estimatedTotal"]},"SandboxExecutionDto":{"type":"object","properties":{"enabled":{"type":"boolean","example":true},"reason":{"type":"string","example":"development_key"}},"required":["enabled","reason"]},"SendOtpResponseDto":{"type":"object","properties":{"messageId":{"type":"string","format":"uuid"},"clientMessageId":{"type":"object","nullable":true,"example":"login_attempt_123456"},"otpMode":{"type":"string","enum":["generated","provided"]},"status":{"type":"string","example":"queued"},"channel":{"type":"string","enum":["sms","telegram"]},"to":{"type":"string","example":"+12345678900"},"requestedTo":{"type":"string","example":"+12345678900"},"apiKeyType":{"type":"string","enum":["live","development"]},"executionMode":{"type":"string","enum":["live","sandbox"]},"simulated":{"type":"boolean"},"pricing":{"$ref":"#/components/schemas/PricingEstimateDto"},"sandbox":{"$ref":"#/components/schemas/SandboxExecutionDto"}},"required":["messageId","clientMessageId","otpMode","status","to","requestedTo","apiKeyType","executionMode","simulated","pricing"]},"SendTemplateMessageDto":{"type":"object","properties":{"to":{"type":"string","example":"+{country_code}{subscriber_number}","description":"Recipient phone number in E.164 format: +{country_code}{subscriber_number}."},"templateId":{"type":"string","format":"uuid","description":"Required Wevlix template UUID. First call GET /v1/projects/{projectId}/whatsapp-account/templates with dashboard authentication, then copy the id of an APPROVED template. Do not use the template name or a Meta/YCloud provider id here."},"components":{"type":"array","maxItems":20,"items":{"type":"object","additionalProperties":true},"description":"Template message components and parameters shared by Meta and YCloud. For an image, video, or document header, pass an HTTPS public link or provider media id in the matching media object. Omit for templates without parameters.","example":[{"type":"body","parameters":[{"type":"text","text":"Taylor"}]}]},"variables":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":4096},"description":"Simple template variable values in placeholder order. Wevlix maps them to YCloud/Meta components. Use components instead for media or advanced buttons; do not send both fields.","example":["Taylor","WVX-1042","Tomorrow"]},"clientMessageId":{"type":"string","example":"order-confirmation-12345","description":"Caller-controlled idempotency identifier for this project."},"countryIso2":{"type":"string","example":"{ISO2_COUNTRY_CODE}","description":"Optional validation hint. Wevlix derives the billing country from the E.164 recipient and rejects a mismatch."},"phoneNumberId":{"type":"string","description":"Optional sender phone-number id from the effective project WABA."}},"required":["to","templateId"]},"MessageTemplateSummaryDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"order_confirmation"},"languageCode":{"type":"string","example":"en"},"category":{"type":"string","example":"UTILITY"}},"required":["id","name","languageCode","category"]},"SendTemplateMessageResponseDto":{"type":"object","properties":{"messageId":{"type":"string","format":"uuid"},"clientMessageId":{"type":"object","nullable":true},"status":{"type":"string","example":"queued"},"to":{"type":"string","example":"+12345678900"},"requestedTo":{"type":"string","example":"+12345678900"},"template":{"$ref":"#/components/schemas/MessageTemplateSummaryDto"},"apiKeyType":{"type":"string","enum":["live","development"],"nullable":true},"executionMode":{"type":"string","enum":["live","sandbox"]},"simulated":{"type":"boolean"},"pricing":{"$ref":"#/components/schemas/PricingEstimateDto"}},"required":["messageId","clientMessageId","status","to","requestedTo","template","apiKeyType","executionMode","simulated","pricing"]},"SendTextMessageDto":{"type":"object","properties":{"to":{"type":"string","example":"+201001234567","description":"Recipient WhatsApp number in E.164 format. This recipient must have sent the project a message within the last 24 hours."},"text":{"type":"string","example":"Thanks for contacting us. How can we help?","maxLength":4096},"clientMessageId":{"type":"string","example":"support-reply-4821-1","description":"Caller-controlled unique identifier for this project."}},"required":["to","text"]},"SendTextMessageResponseDto":{"type":"object","properties":{"messageId":{"type":"string","format":"uuid"},"status":{"type":"string","example":"sent"}},"required":["messageId","status"]},"CreateCustomTemplateDto":{"type":"object","properties":{"name":{"type":"string","example":"order_delivery_update","description":"Meta template name. Use lowercase letters, numbers, and underscores."},"category":{"type":"string","enum":["UTILITY","MARKETING"]},"language":{"type":"string","example":"en_US"},"parameterFormat":{"type":"string","enum":["POSITIONAL","NAMED"],"default":"POSITIONAL"},"components":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"object","additionalProperties":true},"description":"Meta-compatible HEADER, BODY, FOOTER, and BUTTONS components. The draft remains local until a Wevlix admin approves it.","example":[{"type":"BODY","text":"Hi {{1}}, your order {{2}} is ready.","example":{"body_text":[["Sample Customer","ORD-1001"]]}},{"type":"FOOTER","text":"Reply STOP to opt out."}]}},"required":["name","category","language","components"]},"CreateDefaultAuthTemplateDto":{"type":"object","properties":{"name":{"type":"string","example":"wevlix_otp","description":"Meta template name. Use lowercase letters, numbers, and underscores."},"language":{"type":"string","example":"en_US"},"addSecurityRecommendation":{"type":"boolean","default":true},"codeExpirationMinutes":{"type":"number","default":5,"minimum":1,"maximum":10,"description":"OTP expiration in minutes. The authentication message validity period is set to the same value."}}},"UpdateOutboundStatusWebhookDto":{"type":"object","properties":{"url":{"type":"string","example":"https://example.com/webhooks/wevlix"},"enabled":{"type":"boolean","default":true}},"required":["url"]}}},"externalDocs":{"description":"Wevlix integration guide","url":"https://docs.wevlix.com/docs/public"}}