Developer documentation

xSignal API Integration Guide

Start with the HTTP REST API for SMS, extend customer journeys with WhatsApp, verify phone possession with Reverse OTP, or bind directly over SMPP 3.4 for aggregator-grade throughput. Every channel connects to the same routing, billing, and delivery-report pipeline.

1. HTTP REST API

Use the HTTP REST API when your product, backend, CRM, or campaign platform needs a simple stateless integration for SMS submission.

1.1 Base URL and Authentication

All HTTP send requests go to your assigned xSignal host.

Endpoints
POST https://<your-assigned-host>/api/http/send
POST https://<your-assigned-host>/api/http/send/bulk

Every request must include X-API-Key and X-API-Secret headers. Invalid or inactive credentials return 401 Unauthorized.

Only standard GSM-encoded text is supported. Flash SMS and Unicode SMS are not exposed on this API.

1.2 Send to One or More Recipients

POST /api/http/send sends the same sender and text to every address in receivers. One message record is created per receiver.

Request body
{
  "sender": "ABCDE",
  "receivers": ["2348012345678", "2348098765432"],
  "text": "Your OTP is 482913. It expires in 5 minutes.",
  "sms_type": "TRANSACTIONAL"
}
FieldRequiredNotes
senderYesSender ID or shortcode
receiversYesMSISDNs in international format, no +
textYesPlain GSM text
sms_typeConditionalPROMOTIONAL or TRANSACTIONAL. Omit only if credential has BOTH route configured.
200 response
{
  "sent": 2,
  "messages": [
    {
      "our_message_id": "hx_4f3a2b1c9d8e7f6a",
      "provider_message_id": "MC-998877",
      "receiver": "2348012345678",
      "status": "SENT",
      "provider_status": "PENDING",
      "error_code": null,
      "error_message": null
    }
  ]
}

1.3 Send a Batch of Independent Messages

POST /api/http/send/bulk lets each item have its own sender, receiver, text, and sms_type. The response preserves request order.

Bulk request body
{
  "messages": [
    {"sender": "ABCDEF", "receiver": "2348012345678", "text": "Your OTP is 482913.", "sms_type": "TRANSACTIONAL"},
    {"sender": "ABCDEF", "receiver": "2348098765432", "text": "50% off today only!", "sms_type": "PROMOTIONAL"}
  ]
}

1.4 Message Status Values

StatusMeaning
SENTAccepted by upstream provider, awaiting final delivery confirmation
DELIVEREDConfirmed delivered to handset
FAILEDRejected by provider or failed to send

1.5 Routing Rules

Every HTTP credential has one or more active routes tied to sms_type: PROMOTIONAL or TRANSACTIONAL. xSignal first looks for a route matching the request sms_type, then falls back to a BOTH-type route if one is configured.

1.6 Error Responses

HTTP StatusMeaning
401Invalid X-API-Key or X-API-Secret
404No active route for this credential / sms_type combination
400Invalid sms_type value
502Upstream provider call failed

2. WhatsApp API

Use WhatsApp when you need app-based OTPs, structured customer notifications, rich campaign messages, or support conversations. WhatsApp sending uses either free-text messages inside the 24-hour customer care window or approved templates outside that window.

2.1 Send a Free-text Message

POST /api/wa/nv/send uses the same X-API-Key and X-API-Secret authentication model as the HTTP SMS API.

Free-text sends are deliverable only within WhatsApp's 24-hour customer care window. Outside that window, use an approved template.
Request body
{
  "receiver": "447700900000",
  "message": "Your order has shipped!",
  "sender": "SUPPORT"
}
FieldRequiredNotes
receiverYesRecipient MSISDN, full international format, no + or 00
messageYesFree-text message body
senderNoYour sender alias. Omit to use your default sender.
200 response
{
  "our_message_id": "wa_4f3a2b1c9d8e7f6a",
  "message_uuid": "b1ed0340-f501-4d27-9598-886477478fab",
  "status": "SENT"
}

2.2 Send an Approved Template

POST /api/wa/nv/send-template is used for structured notifications, OTPs, order updates, alerts, and messages outside the 24-hour care window. The template must already be approved.

Template request body
{
  "receiver": "447700900000",
  "template_name": "order_shipped",
  "body_params": ["Jane", "TRK123456"],
  "button_param": null,
  "sender": "SUPPORT"
}
FieldRequiredNotes
receiverYesRecipient MSISDN, same format as free-text sends
template_nameYesOne of your approved WhatsApp templates
body_paramsNoPositional values for {{1}}, {{2}}, and other body placeholders
button_paramNoRequired only when the template has a dynamic URL button
senderNoYour sender alias

2.3 Sender Aliases

GET /api/wa/nv/senders lists the aliases provisioned for your account, such as SUPPORT or BILLING. Pass an alias as sender when you want logs and routing to reflect a specific line of business.

2.4 Managing Templates

Template management uses client portal authentication, not API key authentication. Use X-Client-ID and X-Token headers when creating, listing, syncing, or uploading media for templates.

EndpointPurpose
POST /api/wa/nv/templatesCreate a new template for WhatsApp review
GET /api/wa/nv/templatesList your templates, optionally filtered by status
GET /api/wa/nv/templates/{template_id}Retrieve one template
POST /api/wa/nv/templates/{template_id}/syncRefresh approval status
POST /api/wa/nv/templates/mediaUpload image, video, or document media for media-header templates

2.5 WhatsApp Errors

HTTP StatusMeaning
401Invalid or missing authentication
404No active WhatsApp route, unknown sender alias, or template not found
409Route misconfigured or template not approved yet
400Invalid request body or unsupported media type
402Insufficient wallet balance
502WhatsApp send or template-management call failed upstream

3. Reverse OTP Verification

Reverse OTP proves phone possession by asking the end user to send a one-tap WhatsApp or SMS message back to xSignal. After xSignal confirms the inbound sender, your app asks the user for the OTP you generated and completes the verification with the same session.

Reverse OTP is a pilot integration. xSignal must enable your client_id, encryption credential, webhook signing secret, and approved channels before /verify/start will accept traffic.

3.1 Verification Flow

This public flow diagram shows the integration handoff between your app, the user, xSignal, and the messaging channel. Sensitive security controls are intentionally abstracted.

reverse otp flowsanitized sequence
sequenceDiagram
    autonumber
    actor U as User
    participant CA as Client App
    participant XS as xSignal API
    participant CH as WhatsApp / SMS

    U->>CA: Starts phone verification
    CA->>XS: POST /api/verify/start with encrypted request
    XS-->>CA: Encrypted response with session ID and channel links
    CA-->>U: Shows WhatsApp, SMS, or QR verification option
    U->>CH: Sends the prefilled verification message
    CH->>XS: Delivers inbound verification signal

    alt Possession confirmed
        XS-->>U: Sends OTP on the same channel
        XS-->>CA: Signed webhook: verification.msisdn_confirmed
        U->>CA: Enters OTP or follows prefilled verify link
        CA->>XS: POST /api/verify/confirm with session ID
        XS-->>CA: Signed webhook: verification.success
    else Verification cannot continue
        XS-->>CA: Signed webhook: verification.failed with reason code
        opt Fallback enabled
            XS->>CH: Sends fallback SMS to registered phone
            CH-->>U: Fallback verification prompt
            U->>XS: Completes fallback verification
            XS-->>CA: Signed webhook: verification.success
        end
end

3.2 What You Need

  • client_id: your enabled platform client identifier.
  • encryption credential: shared through a secure channel and stored server-side only.
  • webhook signing secret: used to verify signed xSignal webhook events.
  • Webhook URL: your HTTPS endpoint for verification events.

3.3 Encrypted Start Request

POST /api/verify/start starts a verification session. The request and response payloads are encrypted. Your assigned integration pack provides the exact implementation details privately.

Start request
POST /api/verify/start
Content-Type: application/json

{
  "client_id": "your-client-id",
  "payload": "encrypted_payload"
}
Protected request content
{
  "phone": "08012345678",
  "otp": "482913",
  "nonce": "fresh-random-value",
  "timestamp": 1785600000,
  "wa_number": "2348011119999",
  "sms_channel": "ACMEBANK"
}
FieldRequiredNotes
phoneYesUser phone number. xSignal normalizes common Nigerian formats server-side.
otpYesYou generate the code. xSignal relays it after possession is proven.
nonceYesFresh random value per request. Reuse is rejected as replay.
timestampYesUnix seconds. Requests older than 5 minutes or more than 30 seconds in the future are rejected.
wa_numberNoApproved branded WhatsApp number. Omit to use the shared xSignal default.
sms_channelNoApproved shortcode or alphanumeric Sender ID. Unapproved values return 403.

3.4 Start Response

Read the protected response payload using your private integration details. Render the WhatsApp and SMS links as tap-to-send buttons. Keep the session_id for status polling and confirmation.

Response payload after processing
{
  "session_id": "4783fdd6-c6a7-41d0-bfb9-bd3ba74aecbe",
  "wa_link": "https://wa.me/234XXXXXXXXX?text=VERIFY%20abc123",
  "sms_link": "sms:XXXXX?body=VERIFY%20abc123",
  "ttl_seconds": 300
}

3.5 Confirm and Status

POST /api/verify/confirm is a plain JSON call. Use it only after the session reaches MSISDN_CONFIRMED and your app has validated the OTP entered by the user.

Confirm
POST /api/verify/confirm

{ "session_id": "4783fdd6-c6a7-41d0-bfb9-bd3ba74aecbe" }
Status
GET /api/verify/status/{session_id}

{
  "session_id": "...",
  "status": "PENDING",
  "attempts": 1
}

Status values are PENDING, MSISDN_CONFIRMED, VERIFIED, and FAILED.

3.6 Webhooks

xSignal sends signed JSON events to your webhook URL. Verify every event with the webhook signing secret and the private verification instructions supplied during onboarding.

EventMeaning
verification.msisdn_confirmedUser inbound message matched. Channel may be whatsapp, sms, or fallback_mt_sms.
verification.successYour /verify/confirm call succeeded. This is the completion and billing event.
verification.failedSession failed or needs retry handling. Read reason_code.

3.7 Failure Codes and Billing

Reason CodeMeaningRetry
SENDER_MISMATCHInbound message came from a different number than submitted.User can retry from the correct SIM or WhatsApp number.
SESSION_EXPIREDNo matching inbound message within the 5-minute window.Fallback may reissue the same session through MT SMS.
TOKEN_REUSEDSingle-use link/message token was reused.No action required.
RATE_LIMITEDAttempt cap exceeded.Fallback may reissue through MT SMS.

Billing is charged on a successful /verify/start attempt. A later mismatch, expiry, or failure does not refund the initiated verification cost. If /verify/start returns 402, no session was created and no charge was taken.

3.8 HTTP Errors

StatusWhen
400Malformed protected payload, stale timestamp, missing field, or invalid phone.
401Unknown client_id or not enabled yet.
402Insufficient wallet balance.
403Suspended client_id or unapproved wa_number / sms_channel.
404Unknown or expired session_id.
409Nonce reused, or confirm called before MSISDN_CONFIRMED.
429Per-phone or per-IP rate limit exceeded.
503Server-side service misconfiguration. Contact support.

4. SMPP Guide

Use SMPP 3.4 when you already operate SMPP infrastructure, need persistent high-throughput binds, or want real-time delivery reports pushed over the same session.

4.1 Connection

ParameterValue
ProtocolSMPP v3.4
Host / PortProvided by your account manager. Default service port: 2775
Bind typesbind_transceiver, bind_transmitter, bind_receiver
Enquire-link interval30 seconds recommended
Response timeout30 seconds

4.2 Binding

Send bind_transceiver, bind_transmitter, or bind_receiver with your system_id and password. bind_transceiver is recommended because it lets you submit and receive delivery reports on the same session.

Authentication checks your source IP whitelist where configured, then validates your system_id and password against an active credential.

4.3 Sending with submit_sm

Once bound, send a submit_sm PDU with source_addr, destination_addr, short_message, and data_coding. Use registered_delivery = 1 when you want a delivery receipt pushed back to your session.

xSignal acknowledges with submit_sm_resp before routing upstream. Insufficient wallet balance returns ESME_RSUBMITFAIL. Exceeding TPS returns ESME_RTHROTTLED, so slow down and retry.

4.4 Delivery Reports

If registered_delivery = 1 and your session is still bound when final carrier status returns, xSignal sends deliver_sm to you. Respond with deliver_sm_resp to acknowledge.

4.5 Keepalive and Unbind

Send enquire_link every 30 seconds. Send unbind to close gracefully. If no valid PDU is received within the response timeout, the server may drop the connection.

4.6 SMPP Status Codes

CodeNameMeaning
0x00000000ESME_ROKSuccess
0x00000004ESME_RINVBNDSTSPDU sent before binding
0x00000005ESME_RALYBNDAlready bound on this connection
0x0000000DESME_RBINDFAILBind failed: bad IP or credentials
0x0000000EESME_RINVPASWDInvalid password
0x0000000FESME_RINVSYSIDInvalid system ID
0x00000014ESME_RMSGQFULMessage queue full
0x00000058ESME_RTHROTTLEDRate limit exceeded
-ESME_RSUBMITFAILSubmission failed, for example insufficient balance

5. Getting Credentials

Credentials are provisioned by xSignal. You do not self-register API credentials.

  • HTTP and WhatsApp sending: you receive an X-API-Key and X-API-Secret pair. Multiple HTTP credentials can be issued per app, environment, or message type.
  • Reverse OTP: you receive a client_id, private encryption credential, webhook signing secret, and approved WhatsApp/SMS channels where applicable.
  • SMPP: you receive a system_id, password, and IP whitelist where applicable.
  • WhatsApp templates: template management uses client portal session headers, not API key headers.

Keep API secrets, encryption credentials, webhook signing secrets, and SMPP passwords server-side only.

6. Retrieving API Keys

API keys are retrievable through the client portal, gated behind your session login and a separate numeric passcode. This protects your keys even if a session token leaks.

Portal base
https://cl.xsignalling.xyz/api

Portal key retrieval uses X-Client-ID, X-Token, and X-Passcode headers. Keep your keys secret. They are returned as plain text on request and should be treated like database passwords.

7. Delivery Report Reconciliation

Regardless of protocol, delivery status updates are tracked centrally. For SMPP, delivery reports can also be pushed live through deliver_sm. For Reverse OTP, signed webhooks and /api/verify/status/{session_id} provide the verification backstop.

Delivery / webhook history
GET /api/portal/webhooks

This uses the same X-Client-ID / X-Token authentication as the rest of the portal.

8. Rate Limits and Best Practices

  • Use sms_type correctly: TRANSACTIONAL or PROMOTIONAL.
  • Use WhatsApp templates for messages outside the 24-hour care window.
  • For Reverse OTP, generate a fresh nonce per request, never log private credentials, and verify webhook signatures before trusting events.
  • For SMPP, prefer bind_transceiver and keep the session alive with enquire_link.
  • For HTTP, use /send/bulk for mixed batches instead of looping individual send requests.
  • Never hardcode API secrets or SMPP passwords in client-side code.

9. Support

Contact your xSignal account manager for credential provisioning, Reverse OTP pilot access, sender ID registration, WhatsApp template onboarding, or integration issues.

Contact xSignal