List audit log entries

GET /v1/audit-logs

Account changes (keys, team, webhooks, spend limit, numbers, consent, settings) with actor and IP, newest first. Filters apply before paging. One request scans at most 5,000 entries, so a rarely matching filter can return a short or empty page with has_more true: follow next_cursor until has_more is false. Scope: audit_logs:read.

Send your API key as a bearer token: Authorization: Bearer ssms_sk_.... Test keys run this endpoint against the sandbox; see Authentication for key modes and scopes.

Query parameters

NameTypeRequiredDescription
limitintegerNoDefault 25. Maximum 100. Minimum 1.
cursorstringNo
actionstringNoOne action, or a group prefix with a trailing dot (team., api_key.) Example: api_key.created.
actorstringNoActor id (exact) or part of the actor email (case-insensitive) Example: dev@example.com.
target_typestringNoTarget type, e.g. api_key, member, invite, webhook, number, phone Example: webhook.
created_afterstring (date-time)NoEntries at or after this time (ISO 8601) Example: 2026-09-01T00:00:00Z.
created_beforestring (date-time)NoEntries at or before this time (ISO 8601); a bare date means the end of that day (UTC) Example: 2026-09-30T23:59:59Z.

Results are paged. When has_more is true, pass next_cursor from the response as cursor to fetch the next page.

Responses

StatusMeaningBody
200Audit log entries, newest firstPage of AuditLog
400Invalid filterError
401Missing, malformed, or revoked API keyError
402Billable live calls only: the prepaid credit balance cannot cover the call (insufficient_credits); nothing was done or chargedError
429Rate limit or quota exceededError

200: each item in data (AuditLog)

The body is a page: data (the array), has_more, and next_cursor (null on the last page).

FieldTypeDescription
idstringExample: aud_a1B2c3D4e5F6g7H8.
objectaudit_log
actionapi_key.created, api_key.revoked, api_key.rolled, cli_login.approved, cli_login.denied, team.invite_created, team.invite_accepted, team.invite_revoked, team.member_left, team.member_removed, team.role_changed, webhook.created, webhook.updated, webhook.deleted, webhook.secret_rotated, spend_limit.updated, credits.topped_up, credits.settings_updated, number.purchased, number.released, number.assigned, number.registration_set, number.sender_linked, number.sender_unlinked, registration.approved, live_access.approved, consent.updated, consent.imported, migration.opt_outs_attested, quiet_hours.updated, settings.updated, contacts.imported, contact.topic_updated, segment.created, segment.updated, segment.deleted, topic.created, topic.updated, topic.deleted, automation.created, automation.updated, automation.activated, automation.paused, automation.deleted, schedule.created, schedule.updated, schedule.paused, schedule.resumed, schedule.deleted
actorobject
actor.typeuser, api_key, system
actor.idstring
actor.emailstring
actor.namestring
targetobject
target.typestring
target.idstring
metadataobject
ipstring
created_atstring (date-time)

Errors

StatusWhen
400Invalid filter
401Missing, malformed, or revoked API key
402Billable live calls only: the prepaid credit balance cannot cover the call (insufficient_credits); nothing was done or charged
429Rate limit or quota exceeded

Every error has the same JSON shape, and request_id matches the X-Request-Id response header. Errors lists every code and what to do about it.

json
{
  "error": {
    "code": "invalid_request",
    "message": "What went wrong, in plain words.",
    "param": "the_field",
    "request_id": "req_a1B2c3D4e5F6g7H8"
  }
}

Examples

curl

bash
curl -X GET "https://api.joinsimplesms.com/v1/audit-logs?limit=10" \
  -H "Authorization: Bearer $SIMPLESMS_API_KEY"

Node.js

The Node.js SDK does not wrap this endpoint yet; call it with fetch.

javascript
const res = await fetch('https://api.joinsimplesms.com/v1/audit-logs?limit=10', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.SIMPLESMS_API_KEY}`,
  },
});

if (!res.ok) throw new Error((await res.json()).error.message);
const data = await res.json();

Python

The Python SDK does not wrap this endpoint yet; call it over HTTP.

python
import json, os, urllib.request

req = urllib.request.Request(
    "https://api.joinsimplesms.com/v1/audit-logs?limit=10",
    method="GET",
    headers={
        "Authorization": f"Bearer {os.environ['SIMPLESMS_API_KEY']}",
    },
)
with urllib.request.urlopen(req) as res:
    data = json.load(res)