Accounts
You have used all {{ myCustomer.account_limit }} accounts in your plan. Delete one, or ask us for more.
| Account | Status | Customer | Server | Proxy / exit IP | Last seen | |
|---|---|---|---|---|---|---|
| No accounts yet. Click a “New account” button. | ||||||
| {{ a.name }} {{ channelLabel(a) }} +{{ a.phone }} · {{ a.country }} |
{{ statusLabel(a.status) }}
working…
Code
{{ a.pair_code }}Telegram sent a login code to this number
Pair the phone running the RelayKin SMS app
{{ a.last_error }}
|
{{ a.customer_id ? customerName(a.customer_id) : 'Yours' }} | {{ hostName(a.host_id) }} port {{ a.port }} |
{{ proxyFor(a)?.display }}
server IP
{{ a.current_ip }}
{{ proxyFor(a).country }}
{{ f }}
|
{{ ago(a.last_seen) }} |
Inbox
Not available right now: {{ chatsDown.join(', ') }}
Campaigns
Personalised messages sent slowly, one about every 15 seconds per number. Sending limits and opt-outs always apply, and the campaign waits when it reaches a limit. Message only people who agreed to hear from you: complaints are the fastest way to get a number banned.
New campaign
| Campaign | Number | Status | Progress | Starts | |
|---|---|---|---|---|---|
| No campaigns yet. | |||||
| {{ c.name }} {{ c.template }} |
{{ accountName(c.account_id) }} | {{ c.status }} {{ c.reason }} |
{{ campaignDone(c) }} of {{ campaignTotal(c) }} {{ c.counts.sent||0 }} sent, {{ c.counts.skipped||0 }} skipped, {{ c.counts.failed||0 }} failed
{{ c.counts.replied||0 }} replied, {{ c.counts.opted_out||0 }} opted out · consent only
{{ v.variant }}: {{ v.sent }} sent, {{ replyRate(v) }} replied, {{ v.opted_out }} opted out |
{{ time(c.scheduled_at) }} | |
With small numbers, a difference of a few replies can be chance. Wait for at least a few dozen sends on each side.
Numbers are hidden. Show full numbers (asks you to confirm, and is logged).
Responses, within 7 days of the message
No replies or opt-outs yet.
{{ p.phone }}
replied {{ ago(p.replied_at) }} opted out {{ ago(p.opted_out_at) }}Not delivered
No skipped or failed recipients.
{{ p.phone }} {{ p.status }} {{ p.error }}Usage
| Account | API key | {{ m[1] }} |
|---|---|---|
| Nothing recorded in this period. | ||
| {{ usageAccount(r.account_id) }} | {{ keyName(r.api_key_id) }} | {{ (r.totals[m[0]]||0).toLocaleString() }} |
Counted from when this screen was added. Replies from the inbox, AI and voice appear with no API key.
Agents
| Person | Replies | Chats | Median first response | Average | Ratings |
|---|---|---|---|---|---|
| {{ a.email }} | {{ a.replies }} | {{ a.chats }} | {{ duration(a.median_response_seconds) }} | {{ duration(a.avg_response_seconds) }} | {{ a.ratings ? a.avg_rating.toFixed(1) + ' / 5 (' + a.ratings + ')' : '—' }} |
{{ reportPreview.body }}
Response time runs from a customer's first unanswered message to a person's reply from the Inbox. Ratings come from chats closed with the satisfaction check on. All ratings: {{ n }}★ {{ agentStats.ratings[n]||0 }} ·
AI draft quality
Proxy pool
One per line: scheme://user:pass@host:port, host:port or host:port:user:pass. Each proxy is tested for exit IP, country and datacenter status.
| Proxy | Status | Exit IP | Country / ISP | Risk | Used by | |
|---|---|---|---|---|---|---|
| No proxies. Without a proxy an account uses its server's IP. | ||||||
| {{ p.display }} {{ p.label }} |
{{ p.status }}
{{ p.last_error }} |
{{ p.exit_ip || '—' }}{{ p.latency_ms }} ms |
{{ p.country || '—' }} {{ p.isp }} |
datacenterflagged clean | {{ p.account_id ? accountName(p.account_id) : '—' }} | |
Servers
Ubuntu server with Docker installed; the SSH user must be able to run docker. Allow ports {{ info.port_from }}–{{ info.port_to }} only from this portal's IP ({{ info.public_ip }}).
Alerts go out when disk passes 80% (critical at 90%), memory passes 90% (95%), the load stays above 2 per processor, or free memory stays low enough to leave room for 2 more accounts or fewer. The room estimate keeps 512 MB spare. It allows each account half again its highest use in the last 7 days, at least 100 MB, and 150 MB until accounts have been measured.
Memory per account last 7 days, sampled every 15 minutes
| Account | Now | Average | Highest |
|---|---|---|---|
| {{ m.name }} | {{ m.latest_mb }} MB | {{ m.avg_mb }} MB | {{ m.peak_mb }} MB |
Portal release {{ info.release || 'dev' }}. To go back to the release before, run ./release.sh --rollback in the portal folder on the main server.
Integration API keys
External systems use an API key + secret to send and receive WhatsApp messages through
{{ info.public_url || '(set PORTAL_DOMAIN)' }}/v1. Generating a key gives you the full integration details to send to the other system. Public docs: guide, OpenAPI.
| Base URL | {{ info.public_url }}/v1 |
| X-API-Key | {{ newCreds.api_key }} |
| X-API-Secret | {{ newCreds.api_secret }} |
| Webhook signing secret | {{ newCreds.webhook_secret }} |
Send these details to the system or developer using this key. They include everything needed to connect, including the secrets, so use a secure channel.
{{ newCreds.integration_details }}
{{ keyForm.id ? 'Edit' : 'New' }} API key
Tick or untick accounts to add or remove them. The change applies to this key's next request, and the secret stays the same.
| Name | API key | Accounts | Webhook | Last used | Deliveries 24h | ||
|---|---|---|---|---|---|---|---|
| No API keys yet. | |||||||
| {{ k.name }} revoked |
{{ k.key_id }} |
{{ k.all_accounts ? 'All' : k.account_ids.map(accountName).join(', ') }} | {{ k.webhook_url || 'polling only' }} {{ k.events }} |
{{ ago(k.last_used_at) }} | {{ st }} {{ n }} |
| |
Failed webhook deliveries
| API key | Event | Account | Status | Attempts | Last error | When | |
|---|---|---|---|---|---|---|---|
| {{ d.key_name }} | {{ d.event }} | {{ accountName(d.account_id) }} | {{ d.status==='failed' ? 'failed' : 'retrying' }} | {{ d.attempts }} | {{ d.last_error }} | {{ ago(d.created_at) }} |
Activity & alerts
| Number | To | Status | Next try | Note | |
|---|---|---|---|---|---|
| Nothing is waiting. | |||||
| {{ accountName(m.account_id) }} | {{ m.recipient }} |
{{ m.status }} | {{ m.status==='pending' ? time(m.next_attempt_at) : '' }} | {{ m.last_error }} | |
| When | Who | What | Target | Result | IP |
|---|---|---|---|---|---|
| Nothing recorded yet. | |||||
| {{ time(e.created_at) }} | {{ e.actor }} | {{ e.action }} | {{ e.target }} |
{{ e.status<400 ? 'OK' : 'Failed' }} | {{ e.ip }} |
Passkeys
Sign in with your phone, fingerprint, face or a security key instead of the password. Passkeys stay on your device; the password keeps working as a backup.
Passkeys need the portal to run on a domain.
Security
Emergency lockdown
On since {{ ago(security.lockdown.since) }}, started by {{ security.lockdown.by }}: {{ security.lockdown.reason }}
For a suspected breach. Signs out everyone else, refuses agents and API keys, and stops campaigns, queued sends and webhooks. WhatsApp connections stay up, so nothing needs pairing again.
Status
{{ security.backup.last_error }}
Backups are on this server, so losing the server would lose them too.
Who has access
Last reviewed: {{ security.access_reviewed ? ago(security.access_reviewed) : 'never' }}. Review at least every {{ security.review_days }} days, and remove anyone who has left under Settings.
| Person | Role | Accounts | Passkeys | Last active | Last opened a chat | |
|---|---|---|---|---|---|---|
| {{ p.staff.email }} {{ customerName(p.staff.customer_id) }} | {{ p.staff.role }} | {{ p.staff.role === 'admin' ? 'All' : p.staff.role === 'manager' ? 'All of the customer\'s' : p.staff.all_accounts ? (p.staff.customer_id ? 'All of the customer\'s' : 'All') : (p.staff.account_ids || []).length }} | {{ p.passkeys }} | {{ p.last_seen ? ago(p.last_seen) : 'not signed in' }} | {{ p.last_chat_view ? ago(p.last_chat_view) : 'never' }} |
How long records are kept
Older records are deleted automatically, in days; 0 keeps them. Consent and opt-out records stay until that contact's data is erased, as proof of what they asked for. Messages on WhatsApp are not affected.
Where you're signed in
Your password
{{ isAdmin ? 'Staff' : 'Your team' }}
Agents use only the Inbox of the accounts you choose. Managers run one customer's accounts, Inbox, campaigns, integrations and team, and never see servers, proxies or other customers. Admins can do everything.
Agents use only the Inbox of the accounts you choose. Managers can also add accounts, run campaigns and integrations, and manage the team.
Customers
A customer is a company that uses the portal through its own managers. Each customer sees only its own accounts, Inbox, campaigns, API keys and team, and never your servers, proxies, security settings or other customers. Its managers can add accounts up to the limit you set; new accounts get a free proxy from your pool automatically. Move an existing account to a customer from its Manage window.
Lowering the limit keeps the accounts they have; it only stops new ones.
Their first manager (optional)
The person at the customer who signs in and runs their side. You can add more users later with “Add user”.
Saved replies
One-click answers in the Inbox. Agents can use them; only {{ isAdmin ? 'admins and managers' : 'managers' }} can change them.
ChatGPT connection
Connect a ChatGPT subscription for text AI (POST /v1/ai/respond). Voice notes and text-to-voice use the separate API key in .env.
PORTAL_SECRET_KEY in portal/.env and restart the portal. It encrypts the stored tokens.Failed {{ ai.device.error }}
1. Open {{ ai.device.verification_url }} and sign in to ChatGPT.
2. Enter this code: {{ ai.device.user_code }}
Waiting for you to finish… this page updates by itself. The code works for 15 minutes.
{{ ai.connection.email || ai.connection.account_id }} {{ ai.connection.plan || 'plan unknown' }} {{ ai.connection.status==='ok' ? 'Connected' : 'Reconnect needed' }}
{{ ai.connection.last_error }}
Models: {{ m }}none found yet
Refused by the account: {{ m }}
Last 24 hours: {{ ai.usage_24h.calls }} calls ({{ ai.usage_24h.failed }} failed), {{ ai.usage_24h.input_tokens }} tokens in, {{ ai.usage_24h.output_tokens }} tokens out.
No ChatGPT account is connected.
Test
{{ aiResult.model }} {{ aiResult.text }}
Uptime checks
An outside uptime service, such as Healthchecks.io or Better Stack, alerts you when pings stop: the one fault the portal cannot report itself. Create a check there and paste its ping address here. Saved addresses are stored encrypted and shown shortened.
Alert channels
Secrets show as ••••••••; leave them unchanged to keep the saved value. Each channel fires at or above its minimum level. Calls only ring for new critical problems.