Skip to Content
splashify CLITeam & Agents

Team & Agent management

The team (alias: agents, members) and member (alias: agent) commands mirror the Settings → Agents page in the app. You can list members, invite a new agent, verify the owner OTP, update roles or per-page permissions, resend the invite email, and remove a member — all from the terminal.

Backed by /api/v1/app/team/*. Every call uses your stored oc_live_ token and acts as you (the owner) — only the account owner can manage team members.

Quick start

# 1. Invite an agent with full access — prompts for the OTP afterwards splashify team add \ --name "Alice Smith" \ --email alice@example.com \ --country-code +91 \ --phone 9876543210 \ --role agent \ --all read_write # 2. Type the OTP that lands on your owner email + WhatsApp at the prompt # The CLI calls /verify-otps for you, then the backend emails Alice a # "Set your password" link. # 3. Confirm — Alice now appears on the team list splashify team

How adding a member actually works

The flow is two-step on the backend and the CLI wraps both into a single command by default:

  1. POST /app/team creates the pending member and sends a single 6-digit OTP to YOUR (the owner’s) email and WhatsApp. The new member does not receive anything yet.
  2. POST /app/team/verify-otps confirms the OTP. Only after this step does the backend email the new member their “Set your password” link.

splashify team add runs step 1 immediately, then prompts you for the OTP and runs step 2 inline. Use --otp <code> to skip the prompt (e.g. in a script that read the code from elsewhere) or --no-verify to stop after step 1 and verify later from a different machine.

Important — the OTP goes to the owner, not the invitee. Make sure you have access to the owner email and the owner’s WhatsApp number before running team add, otherwise you will not see the code.

Member-limit gate

Every account starts with 5 team-member slots on an active paid plan plus +1 per Extra Team Member addon unit. The limit is reported on every splashify team call:

{ "success": true, "members": [ ... ], "count": 3, "limit": 5 }

team add returns HTTP 403 when count >= limit — purchase the addon from the app (Settings → Subscriptions) to raise the limit. Members beyond the limit are locked (read-only on the backend); the CLI surfaces their is_locked: true flag.

Roles

Only two role values are accepted:

RoleWhat it does
agent (default)Standard team member — permissions are enforced per page key
managerHigher-tier role — still enforced per page key, but typically granted broader permissions

Anything else is rejected with a 400. The CLI validates the role client-side before the round-trip.

Per-page permissions

A member’s permissions field is a JSON object mapping page keys to access levels. The same keys the app’s Settings → Agents → Edit Permissions dialog uses:

GroupKeys
Coredashboard, messages, contacts
Marketingbroadcasts, templates, media
Intelligenceanalytics, ai-agents, ai-credits
Accountintegrations, wallet, settings, activity-logs

Access levels:

LevelMeaning
noneNo access — the page is hidden from the member
readView only — the member can read but cannot write
read_writeFull access — view and modify

Four ways to build a permissions map

The same flags are accepted on team add, team update, and team set-permissions. They are evaluated in this fixed order, so later flags override earlier ones:

  1. --all <level> — seed every known page key with one level (great for “grant everything, then remove a couple”).
  2. --permissions '<json>' — explicit JSON map; can include any keys (even ones the CLI does not know about).
  3. --rw <keys> / --read <keys> / --none <keys> — comma-separated page keys to set to that level. Use these to fine-tune what --all produced.
# Full access everywhere --all read_write # Read-only by default, but full write on the two pages the agent needs --all read --rw messages,contacts # Explicit JSON — useful if you want a stored config file you can diff --permissions '{"dashboard":"read","messages":"read_write","wallet":"none"}' # Combine: start permissive, lock down billing surfaces --all read_write --none wallet,settings,activity-logs

Custom keys. --permissions accepts arbitrary keys for forward compatibility — if the app adds a new page in the future, you can grant permission to it without waiting for a CLI release. The --rw / --read / --none shortcuts only target the known list above.

How updates merge

team update (and team set-permissions) replace the entire permissions map on the backend. That means an update like:

splashify team set-permissions <id> --rw messages

would send {"messages":"read_write"} and clear every other page back to the default (no entry → no access). When you only want to change a few keys while preserving the rest, fetch the current permissions first and merge them yourself:

CURRENT=$(splashify member <id> | jq -r '.permissions') splashify team set-permissions <id> \ --permissions "$(echo "$CURRENT" | jq '. + {"messages":"read_write"}')"

Or use --all as the baseline (it seeds every known key) before overlaying specific changes:

splashify team set-permissions <id> --all read --rw messages,contacts

Command reference

splashify team — list

splashify team # default: list all members + limit + count splashify team list # alias
Backed byGET /api/v1/app/team

Response shape:

{ "success": true, "members": [ { "member_id": "uuid", "owner_id": "uuid", "name": "Alice Smith", "email": "alice@example.com", "country_code": "+91", "phone": "+919876543210", "role": "agent", "email_verified": true, "phone_verified": true, "status": "active", "is_locked": false, "permissions": "{\"messages\":\"read_write\",\"contacts\":\"read\"}", "created_at": "...", "updated_at": "..." } ], "count": 3, "limit": 5 }

permissions comes back as a JSON-encoded string, not a nested object — the storage format on the backend. Use jq -r '.permissions | fromjson' to expand it.

splashify member <id> — show one

splashify member <member_id>

No dedicated backend endpoint — the CLI fetches the list and filters client-side, same pattern as splashify attribute <id>.

splashify team add — invite a new member

splashify team add \ --name "Bob Roe" \ --email bob@example.com \ --country-code +91 \ --phone 9876543210 \ [--role agent|manager] \ [--all read_write | --permissions '{…}' | --rw --read --none …] \ [--otp 123456 | --no-verify]
FlagRequired?Notes
--nameyesDisplay name
--emailyesWill be lowercased + checked for duplicates
--country-codeyes+91, +1, etc.
--phoneyesDigits only — the country code is concatenated server-side
--rolenoagent (default) or manager
--allnoSeed every page with one level
--permissionsnoExplicit JSON map
--rw / --read / --nonenoOverlay specific keys
--otpnoPass the OTP inline — skips the prompt
--no-verifynoStop after create; verify later from team verify

Backed by POST /api/v1/app/team, then (by default) POST /api/v1/app/team/verify-otps.

The new member only receives their “Set Password” email after verify succeeds.

splashify team verify — confirm the OTP separately

splashify team verify <member_id> --otp <code>
Backed byPOST /api/v1/app/team/verify-otps

Use this when you ran team add --no-verify earlier, or when the OTP arrives on a different device. The --otp flag is interactive-friendly: if omitted, the CLI prompts.

splashify team resend-otp — get a fresh code

splashify team resend-otp <member_id>
Backed byPOST /api/v1/app/team/resend-otps

Generates a new 6-digit OTP and re-sends it to the owner’s email + WhatsApp. The previous OTP for that member is invalidated.

splashify team resend-invite — re-send the Set Password email

splashify team resend-invite <member_id>
Backed byPOST /api/v1/app/team/:member_id/resend-password-email

Useful when the original “Set Password” email never arrived (or expired — the link is valid 24h). Only works while the member is status = "pending"; once they’ve set their password and become active, the backend refuses with HTTP 400.

splashify team update — change role and/or permissions

splashify team update <member_id> [--role agent|manager] \ [--all level | --permissions '{…}' \ | --rw | --read | --none …]
Backed byPUT /api/v1/app/team/:member_id

Only the flags you pass are sent. Pass at least one — calling update with no flags returns a usage error.

splashify team set-role — convenience

splashify team set-role <member_id> agent | manager

Same as team update --role …. Refuses any other flag — use this when you specifically want to flip a role without risking accidental permission changes.

splashify team set-permissions — convenience

splashify team set-permissions <member_id> --all read_write splashify team set-permissions <member_id> --rw messages,contacts --read analytics splashify team set-permissions <member_id> --permissions '{"wallet":"none"}'

Same as team update with only permission flags. Cannot change the role.

splashify team delete — remove a member

splashify team delete <member_id> splashify team rm <member_id> # alias splashify team remove <member_id> # alias
Backed byDELETE /api/v1/app/team/:member_id

Permanent. The member loses access immediately. Locked members (is_locked: true, beyond your current addon-purchased limit) cannot be deleted — renew the Extra Team Member addon first, or wait for the lock to clear naturally.

Common workflows

Invite five agents from a CSV

# csv format: name,email,country_code,phone while IFS=, read -r name email cc phone; do splashify team add \ --name "$name" --email "$email" \ --country-code "$cc" --phone "$phone" \ --role agent \ --all read \ --no-verify done < new-agents.csv # Then verify each one as the OTPs arrive on your phone/email.

List every member who can write to broadcasts

splashify team | jq -r ' .members[] | (.permissions | fromjson) as $p | select($p.broadcasts == "read_write") | "\(.member_id)\t\(.name)\t\(.email)" '

Lock down a member to read-only across the board

splashify team set-permissions <id> --all read

Promote an agent to a manager without changing permissions

splashify team set-role <id> manager

Bulk-remove pending members who never accepted the invite

splashify team | jq -r '.members[] | select(.status == "pending") | .member_id' \ | xargs -I{} splashify team delete {}

Re-send the welcome email to every pending member

splashify team | jq -r '.members[] | select(.status == "pending") | .member_id' \ | xargs -I{} splashify team resend-invite {}

Troubleshooting

“An active plan is required to add team members” — the owner account has no active paid plan. The base limit of 5 is gated on an active subscription; upgrade or renew at Settings → Subscriptions and try again.

“Team member limit reached (N/M)” — purchase the Extra Team Member addon (Settings → Subscriptions → Add-ons) to raise the limit. Each unit grants one slot.

“A team member with this email already exists” — the email is taken across the owner’s team (and globally — emails are unique across all team members). Pick a different address or delete the existing record first.

OTP expired or not found — the OTP is valid for 10 minutes and only 3 verification attempts. Use splashify team resend-otp <id> to start fresh.

“Can only resend invite to pending members” — the member already set their password and is now active. They can log in directly at app.splashifypro.com; the password-reset flow is a separate one they can trigger themselves from the login page.

Member shows is_locked: true — they were added before an Extra Team Member addon expired. Renew the addon to unlock and manage them.

See also