Have an account on the old iSMS? Sign in at cp.isms.gr Move your account
iSMS.gr

SMS API for developers

Updated:

Connect your e-shop, CRM or booking system with a simple JSON API over HTTPS. You send SMS with one call and find out whether they were delivered without setting up a webhook, without a public URL and without a static IP. If you prefer, there is also an SMPP connection on request (see below).

Create an account · Full documentation

Get started in three steps

  1. Create an account and open the API page of the panel. Create a key. It is shown only once, so save it right away.
  2. Send an SMS with the call that follows.
  3. Read the delivery reports from /v1/reports.
curl -X POST https://api.isms.gr/v1/messages \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sender": "MyShop", "to": ["306900000000"], "text": "Your order is on its way", "client_ref": "order-1042"}'

Prefer SMPP?

Besides the JSON API, you can also send through SMPP, if your system (for example a messaging platform or a gateway) speaks that protocol. Access is opened on request: contact us and we will activate it for your account.

  • The connection is encrypted (TLS only) and is made only from the IP addresses you give us.
  • The SMPP password is at most 8 characters, a limit of the protocol itself, and it is separate from your panel password.
  • Messages are charged from the same balance and appear in your history with SMPP as the source.
  • The same rules apply as in the panel and the HTTP API: the blacklist and the spam filter.

See also the FAQ for when SMPP is worth it and when the HTTP API is.

Authentication and rights

Every request sends the key in the header Authorization: Bearer <key>. All requests are made over HTTPS.

Each key has only the rights you gave it:

Right What it allows
send Sending SMS (also to a group) and reading the balance
read Message status and delivery reports
blacklist Viewing and changing the blacklist (off by default)
contacts Contacts and groups: create, update, view, delete (off by default)

This way you give each system only what it needs, for example a reporting tool only read. You can optionally limit a key to specific IPs, but it is not required. A key is revoked immediately from the panel and from that moment answers 401. You can have up to 10 active keys.

The API page of the panel: creating a key with rights and an optional IP restriction

Sending: POST /v1/messages

Field Required What it is
sender yes Sender name, up to 11 Latin characters, digits or dots, or up to 15 digits. It must be approved on your account.
to yes, unless you send group A list of mobile numbers with country code, for example 306900000000. Up to 1,000 per call.
group yes, unless you send to The name of a contact group (upper or lower case does not matter). You send either to or group, not both.
text yes The message.
unicode no true for Unicode (70 characters per part). Default is GSM (160 characters).
schedule_at no Send time, ISO 8601.
client_ref no Your own reference, 1 to 64 characters. See below.

If a number is invalid or has no country code, the whole request is rejected and nothing is sent or charged. You are charged when the message is accepted, from your account balance.

Example response:

{
  "id": "KN-7K3M9-Q2XPD",
  "client_ref": "order-1042",
  "status": "queued",
  "created_at": "2026-10-12T08:20:30Z",
  "scheduled_at": null,
  "cost": "0.03572",
  "recipients": 1,
  "counts": {"queued": 1, "sent": 0, "delivered": 0, "failed": 0, "unknown": 0, "blocked": 0},
  "duplicate": false
}

Money is always returned as a string, in euros, and times are in UTC.

Safe retries with client_ref

If a request times out and you don't know whether it arrived, send it again with the same client_ref. A second SMS is not sent and you are not charged again: you get the original message back with "duplicate": true. We remember the client_ref forever.

Delivery reports without a webhook

You ask, and we give you only what you haven't already received. That's why you need no public URL and no static IP.

curl "https://api.isms.gr/v1/reports?limit=500" \
  -H "Authorization: Bearer YOUR_KEY"
{
  "reports": [
    {"message_id": "KN-7K3M9-Q2XPD", "client_ref": "order-1042", "mobile": "306900000000",
     "status": "delivered", "reason": null, "at": "2026-10-12T08:20:36Z"}
  ],
  "count": 1,
  "ack": "tVEgYU10LopOB6biUNbftQ",
  "next_poll_after": 5
}

How the cycle works:

  1. The call returns a batch of reports and an ack.
  2. After you have stored the batch, you call again with ?ack=<the ack>. This confirms it and brings the next one.
  3. If your system crashed before storing, you don't send the ack and you get the same batch again. Nothing is lost.
  4. When there is nothing new, the list is empty and next_poll_after tells you in how many seconds to ask again.

Each SMS gives one report with its final status, not three intermediate ones. If you don't confirm a batch, you receive it again, so store by message_id and mobile so that a duplicate doesn't confuse you. Reports you have confirmed are kept for 30 days. It needs the read right.

Recipient statuses

Status What it means
queued Accepted, not yet given to the provider.
sent Given to the provider, no final result yet. Don't send it again, it may already have been delivered.
delivered Final. The phone received it.
failed Final. Not delivered. reason says why.
blocked Final. The number was on your blacklist at the moment it was due to be sent.
unknown Final. No result arrived within 72 hours. It may or may not have been delivered.

For each message separately, you can ask GET /v1/messages/{id} or GET /v1/messages?client_ref=....

Contacts and groups

If you keep your customers in your own CRM, you can sync them with the panel and send to a group with a single call. It needs the contacts right.

curl -X PUT https://api.isms.gr/v1/contacts \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contacts": [{"mobile": "306900000000", "name": "Maria", "groups": ["Newsletter"]}]}'
  • Each contact has a required mobile (with country code) and optionally name, surname (up to 100 characters), fields (the contact's fields) and groups. A group that doesn't exist is created.
  • Up to 1,000 contacts per call. Contacts that are rejected are returned with the reason, and the rest are saved normally.
  • With "replace_groups": true, each group named in the request contains exactly the contacts you sent. Those who left the group stay as contacts. Here the request fails as a whole if even one contact is invalid (invalid_contacts), and nothing changes.
  • The fields your account accepts are listed by GET /v1/contact-fields. The list can change, so read it instead of keeping it fixed.
  • Account limit: 100,000 contacts and 500 groups.

For each new contact, or contact added to a group, the panel records that your account declared consent through the API (date, key and group). Consent is your responsibility. Numbers on the blacklist are saved, but get no consent record and do not receive messages.

The other calls:

Call What it does
GET /v1/contacts?mobile=... One contact.
GET /v1/contacts List of contacts, 1,000 per page (page), optionally filtered by group.
DELETE /v1/contacts/{mobile} Delete a contact. Blacklisted numbers are not deleted from here.
GET /v1/groups The groups with their number of contacts.
POST /v1/groups Create a group with {"name": "..."}. The name Blacklist is reserved.
DELETE /v1/groups?name=... Delete a group. The contacts stay.
DELETE /v1/groups/members?name=... Empty the group. The contacts stay.

To send to a group, use the group field in POST /v1/messages.

The blacklist from your own system

Numbers on the blacklist do not receive messages and are not charged. The check applies the same way in the panel, the HTTP API and SMPP. When a customer replies STOP, you can add them automatically (blacklist right):

curl -X POST https://api.isms.gr/v1/blacklist \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": ["306900000000", "306900000001"]}'

There are also GET /v1/blacklist (list, or check one number) and DELETE /v1/blacklist/{mobile}.

Balance

curl https://api.isms.gr/v1/credits -H "Authorization: Bearer YOUR_KEY"
{"credits": "12.34000", "currency": "EUR"}

Limits

  • 120 requests per minute per key.
  • Reports: at least 5 seconds between two calls.
  • Status of one message: up to 10 queries per minute.
  • Up to 1,000 numbers per send and up to 1 MB per request.
  • If you exceed the limits you get 429 with Retry-After. A key that keeps exceeding them is stopped for 15 minutes. If you follow Retry-After and next_poll_after, you will never see it.

Errors

Every error is JSON, with a stable code that does not change:

{"error": "insufficient_balance", "message": "..."}
HTTP Codes What you do
400 invalid_json, invalid_request, invalid_sender, invalid_number, too_many_recipients, blocked, empty_group, group_too_large, too_many_contacts, invalid_contacts, invalid_group, contact_limit, group_limit Fix the request. blocked means the text was rejected by the spam filter. contact_limit and group_limit show that you reached the account limit.
401 unauthorized, invalid_key The key is missing, unknown or revoked.
402 insufficient_balance Your balance is not enough. Nothing was sent or charged.
403 forbidden, account_inactive, ip_not_allowed The key doesn't have the right, or the IP isn't allowed.
404 not_found, group_not_found The message or the group doesn't exist.
409 conflict Another request changed the same contacts or groups at the same moment. Send it again.
413 too_large The request exceeds 1 MB.
429 rate_limited, too_soon, too_many_requests_for_message, locked Wait as many seconds as Retry-After says.
503 no_provider We temporarily can't send. Nothing was charged. Try again with the same client_ref.

The full documentation, with all the fields and ready-made code examples in cURL, Python, PHP, Node.js, Java and Go, is public: my.isms.gr/docs/api. For questions, contact us.