ProSignals API
v1
REST API for sending SMS messages — OTP codes, verification alerts, transactional notifications, and marketing blasts. Single endpoint, Bearer auth, JSON in and JSON out. Get up and running in under five minutes.
Overview
The ProSignals API lets your application send SMS through our carrier network. Common integrations:
- OTP & 2FA — login codes, account verification
- Transactional — order confirmations, payment receipts, shipping
- Reminders — appointments, expiring sessions
- Marketing — campaigns, promotions (with consent)
The API is JSON-only, uses standard HTTP status codes, and is billed on delivery — failed messages refund automatically.
Authentication
Every request must include your API key as a Bearer token in theAuthorization header.
Authorization: Bearer psk_live_a1b2c3d4e5f6g7h8i9j0k1l2
Generate keys at Settings → API Keys. Each key looks like psk_live_…. Treat them like passwords — never commit them to source control or expose them in client-side code.
Base URL
https://signalpro1.com/api/v1
All endpoints are HTTPS only. Requests over plain HTTP are rejected at the edge.
Send an SMS
/sms/sendSend a single message or up to 100 recipients in one call. Each recipient's status is returned in the response — partial successes don't fail the whole request.
Request body
| Field | Type | Description |
|---|---|---|
to required | string | string[] | Phone number in E.164 format (with country code), or an array of up to 100 numbers. |
message required | string | The message text. Long messages are split into multiple SMS segments — each counts toward your bill. |
senderId | string | Alphanumeric sender name shown to the recipient. Subject to operator and country support. |
reference | string | Your own identifier (e.g. order number). Echoed back in the response so you can correlate. |
type | "otp" | "marketing" | "transactional" | Tag the message for billing analytics. If omitted we auto-classify from the body (digit-codes + short bodies → OTP; promo vocab → marketing; else transactional). |
Example request
curl -X POST https://signalpro1.com/api/v1/sms/send \
-H "Authorization: Bearer psk_live_…" \
-H "Content-Type: application/json" \
-d '{
"to": "+60123456789",
"message": "Your verification code is 482915",
"reference": "order-9821"
}'Example response · 201 Created
{
"ok": true,
"campaignId": "camp_2k4j…",
"reference": "order-9821",
"totals": {
"accepted": 1,
"failed": 0,
"invalid": 0
},
"estimatedCost": 0.05,
"currency": "MYR",
"recipients": [
{
"id": "msg_8h3n…",
"to": "+60123456789",
"status": "pending",
"carrierRef": "abc123",
"cost": 0.05,
"country": "MY"
}
]
}The message id is what you use to check delivery status later.
Check message status
/sms/{id}Fetch the current delivery status of a previously sent message. Status flips from pending → sent or failed when the carrier delivery report arrives (typically within seconds).
Example request
curl https://signalpro1.com/api/v1/sms/msg_8h3n… \ -H "Authorization: Bearer psk_live_…"
Example response · 200 OK
{
"id": "msg_8h3n…",
"campaignId": "camp_2k4j…",
"to": "+60123456789",
"message": "Your verification code is 482915",
"status": "sent",
"carrierRef": "abc123",
"cost": 0.05,
"country": "MY",
"charged": true,
"createdAt": "2026-05-16T08:14:22.103Z"
}Check account balance
/balanceReturns your current credit balance in MYR. Useful to gate sends or to surface a low-balance warning inside your own app.
Example request
curl https://signalpro1.com/api/v1/balance \ -H "Authorization: Bearer psk_live_…"
Example response · 200 OK
{
"balance": 42.5000,
"currency": "MYR"
}Error codes
Errors return a JSON body with an error code and a human-readable message. HTTP status mirrors the error class.
| Status | Code | Meaning |
|---|---|---|
| 400 | missing_message | The message body is empty. |
| 400 | missing_to | No recipient phone number(s) provided. |
| 400 | no_valid_recipients | All numbers failed E.164 validation. |
| 401 | missing_api_key | No Authorization header was sent. |
| 401 | invalid_api_key | The key is not recognised or has been revoked. |
| 402 | insufficient_balance | Your account balance can't cover this send. |
| 404 | not_found | The requested message id doesn't belong to your account. |
| 413 | too_many_recipients | More than 100 recipients in a single call. |
| 429 | rate_limit_exceeded | Too many requests — back off and retry. |
Message status values
The status field on a message can be any of:
pendingSubmitted to the carrier, waiting for the delivery report (DLR).
sentCarrier confirmed delivery to the handset. Charged.
failedCarrier rejected the message. Not charged.
invalidNumber failed E.164 validation locally. Never sent. Not charged.
Rate limits
- 100 recipients per
/sms/sendcall - 60 requests / minute per API key
- Burst rejections return
429 Too Many Requestswith aRetry-Afterheader
Need higher throughput? Contact support with your expected volume.
Delivery webhook
Instead of polling, register a callback URL on your API key and we'll POST a signed JSON payload to your endpoint every time a message's status changes. Configure the URL at Settings → API Keys.
Headers
Content-Type: application/json User-Agent: ProSignals/1.0 X-ProSignals-Event: sms.status X-ProSignals-Signature: <hex hmac-sha256 of body, using your webhook secret> X-ProSignals-Attempt: 1
Payload
{
"event": "sms.status",
"id": "msg_8h3n…",
"campaignId": "camp_2k4j…",
"to": "+60123456789",
"status": "sent",
"reference": "order-9821",
"timestamp": "2026-05-16T08:14:31.207Z",
"attempt": 1
}The id matches the message id returned from POST /sms/send. The reference field echoes whatever you supplied on the send call (so you can correlate with your own order id).
Verifying the signature
Compute HMAC-SHA256 of the raw request body using your webhook secret, then compare to the value in the X-ProSignals-Signature header.
# Compute the expected signature, then compare with the header value.
echo -n "$RAW_BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}'Retries
We retry up to 3 times on non-2xx responses or network errors, with delays of 1s → 5s → 30s. After the third failure we give up — partners are responsible for reconciling missed events by polling GET /sms/{id} if needed.
2xx status code within 10 seconds to be considered successful. Heavy processing should be queued for later.