Skip to content
Primal Technologies Primal Connect

A Primal Technologies service

  1. Home
  2. API Reference
API reference

Primal Connect API

A REST API for sending and receiving SMS. Requests are ordinary HTTP calls, responses are JSON, and every call is authenticated with a token tied to your account. All endpoints live under https://app.primalconnect.com/api/.

Changed: the API base address used to be documented as http://api.primalconnect.com/sms. That host is no longer the entry point. Use https://app.primalconnect.com/api/sms.

1.1 Sign up

Sign up here. The response confirms your account number; your API token is emailed to you, not returned on the call. Accounts start on the free Bronze tier.

The token arrives by email, from contact@bigplanettelecom.com. Register with an address you can read, and check your spam folder if nothing arrives within a few minutes. Keeping the token out of the HTTP response is deliberate - an automated sign-up cannot walk away with a working credential.
Resource URLhttps://app.primalconnect.com/api/signup
HTTP methodPOST
DescriptionCreate a Primal Connect account and email its API token
Content typesapplication/json or application/x-www-form-urlencoded
Request fields firstname, lastname, email - all required.
password is optional, and the sign-up form no longer asks for one: the account is used through its token, never through a password login. If you do send one it must be 8 characters or more, and password2 must match it when supplied.
Response fields status, message, timestamp, accountid, emailfrom - the address the token email arrives from.
There is deliberately no token field.

Example request:

curl -X POST https://app.primalconnect.com/api/signup -H "Content-Type: application/json" -d '{ "firstname": "Jane", "lastname": "Doe", "email": "jane@example.com" }'

Example response:

{ "timestamp": "2026-09-29 09:24:11.403 -0400", "status": 201, "message": "Account created. Your account number is 0900000007. We have emailed your API token from contact@bigplanettelecom.com - it is not shown here.", "accountid": "0900000007", "emailfrom": "contact@bigplanettelecom.com" }

Account numbers are ten digits beginning 09. They identify the account; they are not dialable numbers. No North American area code begins with a zero, so they can never collide with a real number.

One account per email address - a repeat address answers status 409. Sign-up is also rate limited per IP address, which answers status 429.

1.2 HTTP methods

Primal Connect uses two HTTP methods:

POST creates something - a new account, or a message to be sent.

GET reads something - queued inbound messages, or account details.

Changed: earlier versions of this page listed PUT and DELETE. The API does not implement them and never did; a PUT or DELETE will not be routed.

1.3 Data formats

Responses are always JSON.

Requests may be sent either as JSON (Content-Type: application/json) or as an ordinary HTML form post (Content-Type: application/x-www-form-urlencoded). Both are accepted on /api/sms and /api/signup, and the field names are the same either way. Earlier versions of this page said JSON was mandatory - it is not.

1.4 Token authentication

Every call is authenticated with the token emailed to you at sign-up. Send it as a token request header:

token: <your token>

The token may also be passed as a token field in the request body instead. Send it one way or the other, not both - if both are present, which one is used depends on the content type: a application/x-www-form-urlencoded request takes the header, a application/json request takes the body.

Do not validate the token's length or character set. This page used to describe it as "a global unique 40-character token" (while the example beside it showed a 32-character one). Neither is a rule you should code against. The token is an opaque, case-sensitive string - store it and send it back exactly as issued.

Managed and carrier accounts continue to have their tokens provisioned through Skynet rather than through the sign-up form. The token behaves identically once issued.

Lost your token? We cannot show it to you again - search your mail for the message from contact@bigplanettelecom.com, or email support1@primaltech.com and we will reissue one.

1.5 Response codes

Read this before writing your error handling. The API answers with HTTP 200 on almost every call, including failures. The result you care about is the status field inside the JSON body. Branch on that, not on the HTTP status line.

Values you will see in the body's status field:

200 - the request succeeded.
201 - the resource was created; sign-up returns this.
400 - a required field is missing or malformed. On /api/sms this means no token was supplied.
401 - the token was not accepted. On /api/sms it did not resolve to an account allowed to send from the from number (see 2.1).
402 - the account has no remaining funds (see 2.1).
409 - that email address is already registered.
429 - rate limited. On /api/sms this means the monthly allowance for your tier is spent (see 2.3); on /api/signup it means too many attempts from one IP address.
500 - unexpected error on our side.
503 - the endpoint is switched off on this server. On /api/sms the SMS API is not enabled; on /api/signup self-serve sign-up is temporarily closed.

Every response also carries a human-readable message and a timestamp. When something fails, the message is the field to log and to show your users.

Using our API

2.1 Send SMS

Resource URLhttps://app.primalconnect.com/api/sms
HTTP methodPOST
DescriptionSend a text message
Custom headerstoken: <your token>
Content typesapplication/json or application/x-www-form-urlencoded
Request fields from - required. The 10-digit number the message is sent from. It must be a number on your account
to - required. The 10-digit destination number
text - required. The message body
token - optional. Your API token, if you are not sending it as the token header. Send it one way or the other, not both (see 1.4)
Changed: from is now required. This page previously listed the request as "to, text" only. A request without from will not be delivered.

Every response carries timestamp, status and message. Read status out of the body - it is the result of your request. The HTTP status line is always 200 for this endpoint.

{ "timestamp": "2026-09-28 09:24:11.403 -0400", "status": 200, "message": "Text Message Sent Successfully." }

The values /api/sms answers in status:

statusMeaningWhat to do
200 The message was accepted for delivery. -
400 No token was supplied, in the header or the body. Send the token header.
401 The token does not identify an account that can send from this from number. Check the token, and that from is a number on your account.
402 The account has no remaining funds. Top the account up, or contact sales@primaltech.com.
429 The monthly message allowance for your tier is used up. The message names the tier, the allowance and when it resets. See 2.3. Wait for the reset, or change tier.
500 The message could not be accepted. Safe to retry. If it persists, contact support with the timestamp.
503 The SMS API is not enabled on this server. Contact info@primaltech.com.
A status other than 200 means the message was not sent. Nothing is queued and nothing is retried for you. Until recently this endpoint answered 200 and "Text Message Sent Successfully." even for a message the SMS server had rejected - if your integration treats every call as a success, this is the change to handle.

A failure has the same shape as a success:

{ "timestamp": "2026-10-05 14:08:13.369 -0400", "status": 401, "message": "Message not sent. The token does not identify an account that can send from this number." }

2.1.1 curl example request

curl -X POST https://app.primalconnect.com/api/sms \ -H "token: <your token>" \ -H "Content-Type: application/json" \ -d '{ "from": "4165555555", "to": "4165558888", "text": "This is Primal Connect API" }'

The same call as a form post:

curl -X POST https://app.primalconnect.com/api/sms \ -H "token: <your token>" \ -d "from=4165555555&to=4165558888&text=This is Primal Connect API"

2.2 Receive SMS

There are two ways to receive replies. Which one applies to your account depends on whether a callback URL has been configured for it in Skynet:

A callback URL is set - we POST each inbound message to that URL as it arrives. See 2.2.1.

No callback URL is set - inbound messages are queued for you and you collect them by polling. See 2.2.2.

Contact support1@primaltech.com to have a callback URL added to your account.

2.2.1 Callback URL

We send an HTTP POST to your URL. The body is JSON:

{ "from": "4165555555", "to": "4165558888", "text": "This is a replied text message from mobile", "systemReceivedTime": "2026-09-28 09:24:11.403" }
Two things to code around.

The request arrives with Content-Type: application/x-www-form-urlencoded even though the body is JSON. Read the raw request body and parse it as JSON - do not rely on your framework's form parsing, which will not decode it.

Your token is not included in the callback body. Authenticate the callback by whatever means suits your endpoint, such as a secret path segment.
Removed: this page used to describe a "GET callback URL" mode that appended the message as query parameters. That mode is not implemented. Every callback is a POST with a JSON body.

2.2.2 Polling for messages

If no callback URL is configured, inbound messages are held for you and returned by a GET on the same resource:

Resource URLhttps://app.primalconnect.com/api/sms
HTTP methodGET
DescriptionRetrieve messages queued for your account
Query parameterstoken - your token
curl "https://app.primalconnect.com/api/sms?token=<your token>"

Messages waiting:

{ "timestamp": "2026-09-28 09:24:11.403 -0400", "status": 200, "message": "Success, 1 messages", "result": [ { "from": "4165555555", "to": "4165558888", "text": "This is a replied text message from mobile", "systemReceivedTime": "2026-09-28 09:24:11.403" } ] }

Nothing waiting - note that result is absent rather than empty:

{ "timestamp": "2026-09-28 09:24:11.403 -0400", "status": 200, "message": "Success, No message" }
The queue is held in memory, so a restart of the service clears anything not yet collected. Poll often enough that this is not a problem for you, and use a callback URL if you cannot tolerate the loss.

2.3 Monthly allowance

Each account has a monthly message allowance set by its tier. Inbound and outbound messages both count against it.

Bronze10,000 messages per calendar month
Silver5,000,000 messages per calendar month
Gold50,000,000 messages per calendar month

The allowance is checked before the message is sent, so a message over the cap is never delivered and never billed. Once it is spent, /api/sms answers status 429 with a message naming your tier:

{ "timestamp": "2026-09-29 11:02:18.154 -0400", "status": 429, "message": "Monthly message allowance reached for the BRONZE tier (10000 messages). It resets at the start of next month. Contact sales@primaltech.com to change tier." }

The counter resets at the start of the next calendar month, in server local time. To move tier before then, email sales@primaltech.com.

Handle 429 as a pause, not a failure. Retrying immediately will not help - the allowance does not refill until the month turns over. Queue the traffic, or arrange a higher tier before you need it.

Start sending in minutes

Registration is free and your API token is emailed to you within minutes. The first 10,000 messages a month are on us.