Developer Reference

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.

01

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.

02

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.

The plaintext key is shown only once at creation. If you lose it, generate a new one and revoke the old.
03

Base URL

https://signalpro1.com/api/v1

All endpoints are HTTPS only. Requests over plain HTTP are rejected at the edge.

Send an SMS

POST/sms/send

Send 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

FieldTypeDescription
to
required
string | string[]Phone number in E.164 format (with country code), or an array of up to 100 numbers.
message
required
stringThe message text. Long messages are split into multiple SMS segments — each counts toward your bill.
senderId
stringAlphanumeric sender name shown to the recipient. Subject to operator and country support.
reference
stringYour 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

GET/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

GET/balance

Returns 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"
}
07

Error codes

Errors return a JSON body with an error code and a human-readable message. HTTP status mirrors the error class.

StatusCodeMeaning
400missing_messageThe message body is empty.
400missing_toNo recipient phone number(s) provided.
400no_valid_recipientsAll numbers failed E.164 validation.
401missing_api_keyNo Authorization header was sent.
401invalid_api_keyThe key is not recognised or has been revoked.
402insufficient_balanceYour account balance can't cover this send.
404not_foundThe requested message id doesn't belong to your account.
413too_many_recipientsMore than 100 recipients in a single call.
429rate_limit_exceededToo many requests — back off and retry.
08

Message status values

The status field on a message can be any of:

pending

Submitted to the carrier, waiting for the delivery report (DLR).

sent

Carrier confirmed delivery to the handset. Charged.

failed

Carrier rejected the message. Not charged.

invalid

Number failed E.164 validation locally. Never sent. Not charged.

09

Rate limits

  • 100 recipients per /sms/send call
  • 60 requests / minute per API key
  • Burst rejections return 429 Too Many Requests with a Retry-After header

Need higher throughput? Contact support with your expected volume.

10

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.

Your endpoint must return a 2xx status code within 10 seconds to be considered successful. Heavy processing should be queued for later.

Ready to integrate?

Grab a key, fire your first message, see DLR in seconds.