Guides
Team and security
Roles, invitations, two-factor login, sessions, the security log, email verification, password rules and API keys.
A workspace is one account. The people who log in to it are members, each with a role.
In the dashboard: Settings → Account → Team and Security, and Developers → API Keys.
Roles
Roles are ordered; each can do everything the ones before it can.
| Role | Can do |
|---|---|
| viewer | Read agents, calls, batches, numbers, knowledge bases and settings, plus the balance, plans and prices. Manage their own password, two-factor login and sessions. Cannot read the ledger, invoices, message log, failed jobs or security log |
| member | Also create and change agents, knowledge bases, batches, workflows and campaigns, and place calls |
| admin | Also phone numbers, SIP trunks, provider keys, custom models, API keys, compliance settings, the do-not-call list, account settings, sub-accounts, webhook test and resend, failed jobs, the message log, billing records, the team and the security log |
| owner | Also billing changes (plan, top-ups, tax details, alerts), transferring ownership and deleting the workspace |
An API key acts as admin. It cannot top up the wallet or change the plan.
A request the role does not allow is 403:
{"error": 403, "message": "Your role (viewer) can't change phone numbers. It needs admin access; ask an owner or admin of the workspace."}GET /auth/me returns your member record and role. GET /team/permissions returns the rule table the server enforces.
Invite people
curl -X POST https://api.sevennadi.si/team/invites \
-H "Authorization: Bearer vs-0123456789abcdef0123456789abcdef" \
-H "Content-Type: application/json" \
-d '{"email": "ravi@example.test", "role": "member"}'The response (201) describes the invitation, with expires_at and who sent it. The person gets an email with a link valid for 7 days, and finishes with a name and password.
| Situation | Answer |
|---|---|
| Already a member | 409 This person is already a member of the workspace |
| Already invited | 409 This person already has a pending invitation. Resend it instead. |
| Address has a login in another workspace | 409 This email address already has a login in another workspace |
| Admin inviting an owner | 403 Only an owner can add, change or remove an owner. |
GET /team/invites lists pending invitations, POST /team/invites/{invite_id}/resend sends the email again, and DELETE /team/invites/{invite_id} withdraws one.
Manage members
GET /team/memberslists members.PATCH /team/members/{member_id}with{"role": "admin"}or{"disabled": true}.DELETE /team/members/{member_id}removes someone.
Guard rails: nobody changes their own role, disables their own login or removes themself. Only an owner touches an owner. A workspace always keeps at least one active owner.
Owners only: POST /team/transfer-ownership with {"member_id", "password"}, and DELETE /team/workspace with {"password", "confirm": "<workspace name>"}, which soft-deletes the workspace.
Passwords
- At least 8 characters, at most 200.
- Not your email address.
- Not one of a short list of very common passwords.
- Stored as scrypt hashes.
POST /auth/change-password with {"current_password", "new_password"} keeps your current session and ends the others. POST /auth/forgot-password with {"email"} gives the same answer whether or not the address exists; its link works once, for one hour. POST /auth/reset-password with {"token", "password"} ends every session of that login.
Failed logins are throttled: 10 per 15 minutes per email and address, then 429 Too many login attempts. Try again in 15 minutes.
Email verification
Signing up sends a verification link, valid 24 hours and usable once. POST /auth/verify-email with {"token"} confirms it; POST /auth/resend-verification sends another (three an hour).
Unverified logins work. If the operator requires verified email, these answer 403 until the address is confirmed: placing calls, creating and scheduling batches, starting or resuming campaigns, running workflows, and creating API keys.
Two-factor login
Two-factor login uses time-based codes from an authenticator app (TOTP).
POST /auth/2fa/setupreturns{"secret", "otpauth_uri"}. Show the URI as a QR code.POST /auth/2fa/enablewith{"code"}turns it on and returns 8 single-userecovery_codes. Store them.- From then on
POST /auth/loginanswers{"two_factor_required": true, "challenge": "..."}. Finish withPOST /auth/login/2faand{"challenge", "code"}(or"recovery_code") within 5 minutes.
Codes are accepted one step either side of the current time and never twice. Five wrong codes lock the second step for 15 minutes. POST /auth/2fa/disable needs your password and a code or recovery code. These endpoints need a dashboard login; an API key gets 403 This needs a dashboard login, not an API key.
Sessions
A login returns a session token (vs- followed by 32 hex characters) that works as a Bearer token for 7 days.
GET /auth/sessionslists your sessions.DELETE /auth/sessions/{session_id}ends one.POST /auth/sessions/revoke-allwith{"keep_current": true}ends the rest.
Security log
curl "https://api.sevennadi.si/team/audit?event=login_failed&page_size=20" \
-H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"{"page_number": 1, "page_size": 20, "total": 1, "has_more": false, "data": [
{"id": 311, "event": "login_failed", "actor": "ravi@example.test", "member_id": "5a4b3c2d-1e0f-4a9b-8c7d-6e5f4a3b2c1d",
"detail": {"reason": "wrong password"}, "ip": "203.0.113.7", "user_agent": "Mozilla/5.0", "created_at": "2026-10-13T11:20:00Z"}
]}It records logins and failed logins, password and two-factor changes, invitations, role changes, and API keys created and revoked. page_size is at most 100.
API keys
curl -X POST https://api.sevennadi.si/auth/api-keys \
-H "Authorization: Bearer vs-0123456789abcdef0123456789abcdef" \
-H "Content-Type: application/json" \
-d '{"name": "Production server"}'Response, 201:
{"id": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e", "name": "Production server", "prefix": "vk-01234",
"created_at": "2026-10-13T11:30:00Z", "last_used_at": null, "key": "vk-0123456789abcdef0123456789abcdef"}The full key is shown only in this response. The platform stores a hash, so a lost key cannot be recovered: revoke it and create another. GET /auth/api-keys lists keys by prefix and last_used_at. DELETE /auth/api-keys/{key_id} revokes one.
More on tokens in Authentication.
Limitations
- No external security audit or penetration test has been done.
- No single sign-on, no IP allow-lists for API keys, and no per-key scopes: every API key is an admin.
- An authenticator app is the only second factor, and recovery codes the only fallback.
- Customer data (transcripts, recordings, contact lists) is not encrypted at rest by the platform.
- By default the platform stores emails in a development outbox instead of sending them. The operator must configure SMTP for real invitation and reset emails.