Skip to content

SMS Suppression API Documentation

SMS suppression list management endpoints for browsing, adding, deleting, and aggregating phone numbers (and wildcard patterns) suppressed at the user or list level.

The Reason column is a fixed enumeration. The valid values are:

  • manual
  • optout
  • complaint
  • bounce
  • invalid
  • other

The Source column is a fixed enumeration. The valid values are:

  • manual_entry
  • import
  • api
  • optout_link

The Level column is a fixed enumeration. The valid values for user-authenticated calls are:

  • user
  • list (requires ListID)

Admin-authenticated calls may additionally pass system: smssuppression.add and smssuppression.patterns.add create system-wide suppressions with it, and smssuppression.browse, smssuppression.stats and smssuppression.patterns.browse read them with it (new in v5.9.6).

Phone numbers must be in E.164 format with a leading + (e.g. +15551234567). Patterns use * as a wildcard (e.g. +1555* blocks all numbers starting with +1555).

Browse SMS Suppression List

POST /api.php

API Usage Notes

  • Authentication required: User API Key or Admin API Key
  • The command is registered user,admin: a request carrying both credentials takes the user path unless Access=admin is passed. Existing user-key integrations are unaffected.
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: smssuppression.browse
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
AdminAPIKeyStringNoAdmin API key (privilege SMS). Unlocks the admin behaviour described below.
AccessStringNoSet to admin when calling with an Admin API Key.
LevelStringNoSuppression level to query. One of user (default), list. Admin auth may also pass system.
ListIDIntegerNo*List ID. Required when Level=list. The list must belong to the authenticated user (user auth) or to the account named by UserID (admin auth).
UserIDIntegerNo*Target account. Required under admin auth when Level is user or list; ignored under user auth.
ReasonStringNoFilter by Reason ENUM value.
SearchPatternStringNoSubstring match against PhoneNumber and Notes (always a contains search with no wildcard syntax: pass the literal value to look for).
IsPatternIntegerNoWhen 1, only return wildcard pattern entries. When 0, only return exact-match entries.
StartFromIntegerNoStarting record index for pagination (default: 0).
RetrieveCountIntegerNoNumber of records to retrieve (default: 100, max: 1000).

* ListID is required only when Level=list. UserID is required only under admin auth with Level=user or Level=list.

Admin authentication:

  • Level additionally accepts system, which lists the install-wide suppressions (no UserID needed).
  • For Level=user or Level=list, UserID names the target account (required). The list named by ListID must belong to that account. A restricted sub-admin can only target accounts inside its allowed user groups.
  • Additional error codes under admin auth: 5001 UserID missing or invalid, 5002 user not found, 5003 user outside the user groups this admin account may access.

Response Shape:

Suppressions is a JSON array of suppression rows, ordered by CreatedAt DESC. TotalRecords reflects the filtered count, so paging math always lines up with the rendered page.

A retrieval failure is never reported as an empty list. If the suppression entries cannot be read, the response is Success: false with ErrorCode: [5] and no TotalRecords / Suppressions keys. Success: true with TotalRecords: 0 therefore means the filter genuinely matched nothing (or, for Level=list, that the list has no suppressed numbers). It is never a masked error.

Behavior change in v5.9.3

Before v5.9.3, Level=list always returned Success: true, TotalRecords: 0, Suppressions: [] for every account, because the list owner was resolved from a table that does not exist and the resulting query failure was reported as an empty success. List-level browsing now returns the correct rows, and its TotalRecords agrees with smssuppression.stats for the same list.

Integrations that treat TotalRecords: 0 as "empty" must now also handle Success: false with ErrorCode: [5].

bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.browse",
    "APIKey": "your-api-key",
    "Level": "user",
    "Reason": "bounce",
    "SearchPattern": "+1555",
    "StartFrom": 0,
    "RetrieveCount": 50
  }'
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.browse",
    "AdminAPIKey": "your-admin-api-key",
    "Access": "admin",
    "Level": "system",
    "RetrieveCount": 50
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "TotalRecords": 1,
  "Suppressions": [
    {
      "SuppressionID": "1",
      "SuppressionType": "user",
      "RelUserID": "1",
      "RelListID": null,
      "PhoneNumber": "+15551234567",
      "PhoneNumberNormalized": "15551234567",
      "IsPattern": "0",
      "Reason": "bounce",
      "Source": "api",
      "Notes": "Hard bounce",
      "AddedByUserID": "1",
      "AddedByAdminID": null,
      "CreatedAt": "2026-04-30 14:27:45",
      "UpdatedAt": "2026-04-30 14:27:45"
    }
  ]
}
json
{
  "Success": false,
  "ErrorCode": [1]
}
json
{
  "Success": false,
  "ErrorCode": [5]
}
txt
0: Success
1: Invalid Level value
2: Missing ListID when Level=list
3: ListID does not belong to the authenticated user
4: Invalid Reason value
5: Suppression entries could not be retrieved (internal error; the cause is
   written to the application log). Retry; if it persists, contact the operator.
5001: UserID missing or invalid (admin auth, Level=user or Level=list)
5002: User not found (admin auth)
5003: User outside the user groups this admin account may access (admin auth)

SMS Suppression Stats

POST /api.php

Returns the total count and a per-type / per-reason breakdown for the authenticated user (user auth), or for the install or a chosen account (admin auth). All ENUM values are always present in ByType and ByReason (zero when absent) so typed clients see a stable shape.

API Usage Notes

  • Authentication required: User API Key or Admin API Key
  • The command is registered user,admin: a request carrying both credentials takes the user path unless Access=admin is passed. Existing user-key integrations are unaffected.
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: smssuppression.stats
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
AdminAPIKeyStringNoAdmin API key (privilege SMS). Unlocks the admin behaviour described below.
AccessStringNoSet to admin when calling with an Admin API Key.
LevelStringNoOptional Level filter. One of user, list. Admin auth may also pass system.
ListIDIntegerNo*List ID. Required when Level=list. The list must belong to the authenticated user (user auth) or to the account named by UserID (admin auth).
UserIDIntegerNo*Target account (admin auth only). Optional; required with Level=user or Level=list.

* ListID is required only when Level=list.

Admin authentication:

  • With no Level and no UserID the figures are install-wide (every level, every account), the numbers the admin SMS Suppression screen shows.
  • Level=system counts the install-wide rows only.
  • UserID (optional, required with Level=user / Level=list) scopes the figures to that account. Error codes 5001 / 5002 / 5003 as for smssuppression.browse.
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.stats",
    "APIKey": "your-api-key"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "Total": 1240,
  "ByType": {
    "System": 0,
    "User": 1100,
    "List": 140
  },
  "Patterns": 12,
  "ByReason": {
    "Manual": 5,
    "Optout": 312,
    "Complaint": 14,
    "Bounce": 871,
    "Invalid": 0,
    "Other": 38
  }
}
json
{
  "Success": false,
  "ErrorCode": [1]
}
txt
0: Success
1: Invalid Level value
2: Missing ListID when Level=list
3: ListID does not belong to the authenticated user
5001: UserID missing or invalid (admin auth, Level=user or Level=list)
5002: User not found (admin auth)
5003: User outside the user groups this admin account may access (admin auth)

Add to SMS Suppression List

POST /api.php

Accepts a single phone number or a bulk payload. Phone numbers may be exact (e.g. +15551234567) or patterns (containing *). Pattern detection happens automatically: +1555* is stored as a pattern and matched at SMS send-time.

API Usage Notes

  • Authentication required: User API Key or Admin API Key
  • When using both auth types simultaneously, pass Access=user to disambiguate
  • System-wide entries (Level=system) require Admin API Key
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: smssuppression.add
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
AdminAPIKeyStringNoAdmin API key for authentication
AccessStringNoWhen the request bears both admin and user credentials, set to user or admin to choose the authentication path.
PhoneNumberStringNo*Single phone number to add (E.164 format with +).
PhoneNumbersStringNo*JSON-encoded array of phone numbers, or newline-separated phone numbers.
LevelStringNoOne of user (default), list. Admin auth may also pass system.
UserIDIntegerNo*Target user ID. Required when admin-authed and Level is user or list. Ignored for user-authed calls (always the authenticated user).
ListIDIntegerNo*List ID. Required when Level=list. The list must belong to the target user (this applies to both user and admin auth: the list's RelOwnerUserID must equal the supplied or authenticated UserID).
ReasonStringNoOne of the Reason ENUM values. Defaults to manual.
SourceStringNoOne of the Source ENUM values. Defaults to api.
NotesStringNoFree-text notes attached to the entry.

* At least one of PhoneNumber or PhoneNumbers is required. UserID and ListID are conditional on Level and auth context.

bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.add",
    "APIKey": "your-api-key",
    "Access": "user",
    "PhoneNumber": "+15551234567",
    "Level": "user",
    "Reason": "bounce",
    "Notes": "Hard bounce"
  }'
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.add",
    "APIKey": "your-api-key",
    "Access": "user",
    "PhoneNumbers": "[\"+15552223333\",\"+15554445555\"]",
    "Level": "user"
  }'
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.add",
    "APIKey": "your-api-key",
    "Access": "user",
    "PhoneNumbers": "+15552223333\n+15554445555",
    "Level": "user"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "SuppressionID": 42
}
json
{
  "Success": true,
  "ErrorCode": 0,
  "TotalAdded": 2,
  "TotalFailed": 1,
  "FailedPhoneNumbers": ["not-a-phone"]
}
json
{
  "Success": false,
  "ErrorCode": [1]
}
txt
0: Success
1: Missing input: neither PhoneNumber nor PhoneNumbers was provided
2: Invalid Level value (or Level=system attempted with user auth)
3: Missing UserID (admin-authed only, when Level is user or list)
4: Missing ListID when Level=list
5: ListID does not belong to the target user (or does not exist)
6: Invalid Reason value
7: Invalid Source value
8: Add failed (single path, see server log; typically an invalid phone number)
9: PhoneNumbers parsed to an empty list
10: Target UserID does not exist (admin-authed only)

Delete from SMS Suppression List

POST /api.php

Accepts either a single suppression ID or a bulk payload of IDs. Under user auth only entries owned by the authenticated user (and not system-level) can be deleted; admin auth widens this, see below.

API Usage Notes

  • Authentication required: User API Key or Admin API Key
  • The command is registered user,admin: a request carrying both credentials takes the user path unless Access=admin is passed. Existing user-key integrations are unaffected.
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: smssuppression.delete
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
AdminAPIKeyStringNoAdmin API key (privilege SMS). Unlocks the admin behaviour described below.
AccessStringNoSet to admin when calling with an Admin API Key.
SuppressionIDIntegerNo*Single SuppressionID to remove.
SuppressionIDsStringNo*JSON-encoded array of SuppressionIDs to remove.

* At least one of SuppressionID or SuppressionIDs is required. When SuppressionIDs is set, the response uses the bulk shape (with TotalDeleted, TotalFailed, FailedSuppressionIDs).

Admin authentication:

  • System-level rows are deletable (they were previously refused with ErrorCode: [3] under user auth, which is unchanged for user callers).
  • Rows of any account are deletable by an unrestricted admin. A restricted sub-admin may only delete rows whose owning account is inside its allowed user groups; other rows fail with ErrorCode: [3] (single) or land in FailedSuppressionIDs (bulk).
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.delete",
    "APIKey": "your-api-key",
    "SuppressionID": 42
  }'
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.delete",
    "APIKey": "your-api-key",
    "SuppressionIDs": "[42, 43, 44]"
  }'
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.delete",
    "AdminAPIKey": "your-admin-api-key",
    "Access": "admin",
    "SuppressionID": 42
  }'
json
{
  "Success": true,
  "ErrorCode": 0
}
json
{
  "Success": true,
  "ErrorCode": 0,
  "TotalDeleted": 2,
  "TotalFailed": 1,
  "FailedSuppressionIDs": [44]
}
json
{
  "Success": false,
  "ErrorCode": [3]
}
txt
0: Success
1: Missing input: neither SuppressionID nor SuppressionIDs was provided
2: Invalid SuppressionID (single path)
3: Suppression not found, is system-level, or does not belong to the authenticated user (single path, user auth). Under admin auth: not found, or owned by an account outside the user groups this admin account may access
4: Removal failed (single path, see server log)
5: SuppressionIDs JSON could not be decoded as a non-empty array

Browse SMS Suppression Patterns

POST /api.php

Returns wildcard pattern entries (numbers containing *) owned by the authenticated user (user auth), or across the install or a chosen account (admin auth). Useful for rendering a dedicated "patterns" tab without filtering through the full smssuppression.browse payload.

API Usage Notes

  • Authentication required: User API Key or Admin API Key
  • The command is registered user,admin: a request carrying both credentials takes the user path unless Access=admin is passed. Existing user-key integrations are unaffected.
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: smssuppression.patterns.browse
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
AdminAPIKeyStringNoAdmin API key (privilege SMS). Unlocks the admin behaviour described below.
AccessStringNoSet to admin when calling with an Admin API Key.
LevelStringNoOptional level filter. One of user, list. When omitted, returns all patterns owned by the user. Admin auth may also pass system.
ListIDIntegerNo*List ID. Required when Level=list. The list must belong to the authenticated user (user auth) or to the account named by UserID (admin auth).
UserIDIntegerNo*Target account (admin auth only). Optional; required with Level=user or Level=list.

* ListID is required only when Level=list.

Admin authentication:

  • With no Level and no UserID every pattern at every level is returned.
  • Level=system returns the install-wide patterns only.
  • UserID (optional, required with Level=user / Level=list) scopes to that account. Error codes 5001 / 5002 / 5003 as for smssuppression.browse.
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.patterns.browse",
    "APIKey": "your-api-key"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "Patterns": [
    {
      "SuppressionID": "4",
      "SuppressionType": "user",
      "RelUserID": "1",
      "RelListID": null,
      "PhoneNumber": "+1555*",
      "PhoneNumberNormalized": "+1555*",
      "IsPattern": "1",
      "Reason": "manual",
      "Source": "api",
      "Notes": "",
      "AddedByUserID": "1",
      "AddedByAdminID": null,
      "CreatedAt": "2026-04-30 14:27:55",
      "UpdatedAt": "2026-04-30 14:27:55",
      "ListName": null
    }
  ]
}
json
{
  "Success": false,
  "ErrorCode": [1]
}
txt
0: Success
1: Invalid Level value
2: Missing ListID when Level=list
3: ListID does not belong to the authenticated user
5001: UserID missing or invalid (admin auth, Level=user or Level=list)
5002: User not found (admin auth)
5003: User outside the user groups this admin account may access (admin auth)

Add SMS Suppression Pattern

POST /api.php

Adds a single wildcard pattern entry. The class auto-detects pattern entries by the presence of *. Passing a non-pattern phone number will create an exact-match suppression instead. Reason is hardcoded to manual for parity with the Octeth UI; use smssuppression.add if you need a different Reason.

API Usage Notes

  • Authentication required: User API Key or Admin API Key
  • When using both auth types simultaneously, pass Access=user to disambiguate
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: smssuppression.patterns.add
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
AdminAPIKeyStringNoAdmin API key for authentication
AccessStringNoChoose user or admin when both credentials are supplied.
PhoneNumberStringYesPattern (e.g. +1555*).
LevelStringNoOne of user (default), list. Admin auth may also pass system.
UserIDIntegerNo*Target user ID. Required when admin-authed and Level is user or list.
ListIDIntegerNo*List ID. Required when Level=list. The list must belong to the target user (applies to both user and admin auth).
SourceStringNoOne of the Source ENUM values. Defaults to api.
NotesStringNoFree-text notes attached to the entry.

* UserID and ListID are conditional on Level and auth context.

bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.patterns.add",
    "APIKey": "your-api-key",
    "Access": "user",
    "PhoneNumber": "+1555*",
    "Level": "user",
    "Notes": "Block all 1-555 numbers"
  }'
json
{
  "Success": true,
  "ErrorCode": 0,
  "SuppressionID": 42
}
json
{
  "Success": false,
  "ErrorCode": [7]
}
txt
0: Success
1: Missing PhoneNumber
2: Invalid Level value (or Level=system attempted with user auth)
3: Missing UserID (admin-authed only, when Level is user or list)
4: Missing ListID when Level=list
5: ListID does not belong to the target user (or does not exist)
6: Invalid Source value
7: Add failed (see server log; typically an invalid pattern format)
8: Target UserID does not exist (admin-authed only)

Delete SMS Suppression Pattern

POST /api.php

Removes pattern entries by SuppressionID. Functionally identical to smssuppression.delete, provided as a separate endpoint for consistency with the patterns namespace.

API Usage Notes

  • Authentication required: User API Key or Admin API Key
  • The command is registered user,admin: a request carrying both credentials takes the user path unless Access=admin is passed. Existing user-key integrations are unaffected.
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: smssuppression.patterns.delete
SessionIDStringNoSession ID obtained from login
APIKeyStringNoAPI key for authentication
AdminAPIKeyStringNoAdmin API key (privilege SMS). Unlocks the admin behaviour described below.
AccessStringNoSet to admin when calling with an Admin API Key.
SuppressionIDIntegerNo*Single SuppressionID to remove.
SuppressionIDsStringNo*JSON-encoded array of SuppressionIDs to remove.

* At least one of SuppressionID or SuppressionIDs is required.

Admin authentication:

  • System-level rows are deletable (they were previously refused with ErrorCode: [3] under user auth, which is unchanged for user callers).
  • Rows of any account are deletable by an unrestricted admin. A restricted sub-admin may only delete rows whose owning account is inside its allowed user groups; other rows fail with ErrorCode: [3] (single) or land in FailedSuppressionIDs (bulk).
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.patterns.delete",
    "APIKey": "your-api-key",
    "SuppressionID": 42
  }'
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.patterns.delete",
    "APIKey": "your-api-key",
    "SuppressionIDs": "[42, 43]"
  }'
json
{
  "Success": true,
  "ErrorCode": 0
}
json
{
  "Success": true,
  "ErrorCode": 0,
  "TotalDeleted": 2,
  "TotalFailed": 0,
  "FailedSuppressionIDs": []
}
json
{
  "Success": false,
  "ErrorCode": [3]
}
txt
0: Success
1: Missing input: neither SuppressionID nor SuppressionIDs was provided
2: Invalid SuppressionID (single path)
3: Suppression not found, is system-level, or does not belong to the authenticated user (single path, user auth). Under admin auth: not found, or owned by an account outside the user groups this admin account may access
4: Removal failed (single path, see server log)
5: SuppressionIDs JSON could not be decoded as a non-empty array

Clear SMS Suppression Cache

POST /api.phpNew in v5.9.6

Flushes every SMS suppression cache entry in Redis, the "Clear cache" action of the admin SMS Suppression screen. Use it after bulk changes made outside the API (direct database edits, imports) so the send path re-reads the table.

API Usage Notes

  • Authentication required: Admin API Key (privilege SMS)
  • Legacy endpoint access via /api.php only (no v1 REST alias configured)

Request Body Parameters:

ParameterTypeRequiredDescription
CommandStringYesAPI command: smssuppression.cache.clear
AdminAPIKeyStringYesAdmin API key
bash
curl -X POST https://example.com/api.php \
  -H "Content-Type: application/json" \
  -d '{
    "Command": "smssuppression.cache.clear",
    "AdminAPIKey": "your-admin-api-key"
  }'
json
{
  "Success": true,
  "ErrorCode": 0
}
json
{
  "Success": false,
  "ErrorCode": [1],
  "ErrorText": "Cache clear failed, see the server log"
}
txt
0: Success
1: Cache clear failed (see server log)

Any questions? Contact us.