eSMS AfricaeSMS Africa
API ReferenceSMS API

Team roles and audit log

Invite teammates with a role (owner, admin, sender, approver, viewer), work inside a team workspace with X-Workspace, per-member API keys, and the audit log of who did what.

Every account has one workspace. The owner (or an admin) invites people by email with a role. Members work inside the owner's account: its balance, sender IDs, contacts, templates and campaigns. Every action is recorded in the audit log.

Roles

RoleCan
ownerEverything, including billing and the team. The account holder (not stored as a member).
adminEverything except ownership: team, workspace settings, webhooks, sender ID requests, sending, approving.
senderSend messages, run campaigns, manage contacts and templates, create their own API keys. Not: team, workspace settings, webhook settings, alerts, sender ID requests, top-ups, approving campaigns.
approverRead-only, plus approve or reject campaigns that need sign-off.
viewerRead-only: reports, logs, contacts, campaigns.

Read-only roles can still use calculation endpoints that change nothing (rate check, number validation, previews, template render). A blocked action returns 403 with code role_forbidden and the reason.

Approvals are maker-checker: the person who submitted a campaign can't approve it (403 self_approval), even if they are an approver or admin. See Campaigns.

Team endpoints

These are dashboard (signed-in) endpoints.

MethodPathDescription
GET/v1/teamMembers (owner first) with role, status (active / pending), can_manage, my_role, roles.
GET/v1/team/rolesRole list with descriptions.
POST/v1/team/invite{email, role} - owner or admin. role is admin, sender, approver or viewer. An email invitation is sent.
PATCH/v1/team/{member_id}{role} - owner or admin.
DELETE/v1/team/{member_id}Remove a member; their API keys stop working.
GET/v1/workspacesThe workspaces you can work in (own + teams you joined) and pending invites.
POST/v1/workspaces/{id}/acceptAccept an invitation (sign in with the invited email).
POST/v1/workspaces/{id}/leaveLeave a team, or decline an invitation.

Working in a team workspace

Send the workspace id in a header on every request:

X-Workspace: 603

The API then acts on that workspace's account with your role. A workspace you don't belong to returns 403 not_a_member. API keys ignore the header: a key always acts in the workspace it was created in. The dashboard sets this header for you when you pick a workspace in the switcher. Platform admin rights never apply inside a customer workspace.

API keys created by members

A key created by a team member belongs to the workspace (it bills the workspace balance) and carries the creator's role: a sender's key can send but can't manage the team or webhooks, and a viewer or approver can only create query keys. Members below admin can revoke only the keys they created. Keys list created_by and created_role. Removing a member disables their keys.

Audit log

Owner and admins only.

GET https://sms.esmsafrica.io/v1/audit-logs?action=campaign.&actor=&q=&date_from=&date_to=&page=0&limit=50
GET https://sms.esmsafrica.io/v1/audit-logs/export

Each entry: at, actor (email, or null for actions the platform took such as a campaign finishing), role, via (web, api or system), action, target_type, target_id, summary, meta, ip. action filters by prefix. The export is CSV.

Recorded actions include: message.sent and message.scheduled (dashboard sends; API sends are in the request log), bulk.sent, campaign.created, campaign.launched, campaign.submitted, campaign.approved, campaign.rejected, campaign.pause, campaign.resume, campaign.cancel, campaign.retry_failed, campaign.duplicated, campaign.deleted, campaign.test_sent, campaign.paused and campaign.completed (system), import.uploaded, import.pasted, import.gsheet, contacts.imported, contact.saved, contact.updated, contact.deleted, group.*, template.*, api_key.created, api_key.revoked, team.invited, team.role_changed, team.removed, team.joined, team.left, settings.updated.

Example

# A member's signed-in session token (API keys ignore X-Workspace):
curl https://sms.esmsafrica.io/v1/campaigns \
  -H "Authorization: Bearer $ESMS_SESSION_TOKEN" -H "X-Workspace: 603"
// Keys created by a member already act in the member's workspace with their role.
const esms = new Esms(process.env.ESMS_MEMBER_KEY);
const list = await esms.campaigns.list({ status: "pending_approval" });
esms = Esms(api_key=os.environ["ESMS_MEMBER_KEY"])
pending = esms.campaigns.list(status="pending_approval")
$esms = new \Esms\Client(getenv('ESMS_MEMBER_KEY'));
$pending = $esms->campaigns->list(['status' => 'pending_approval']);
client := esms.New(os.Getenv("ESMS_MEMBER_KEY"))
pending, _ := client.Campaigns.List(ctx, esms.ListQuery{"status": "pending_approval"})

On this page