Install
openclaw skills install @whatsable/agent-skills-by-notifyerCreate and manage a Notifyer by WhatsAble account — signup, login, retrieve the authenticated user, check WhatsApp connection status, manage subscription plans, manage team members, assign roles, configure workspace labels, and retrieve the Developer API key. Use this skill any time you need to authenticate against the Notifyer Console API, set up a new workspace, or prepare the identity and infrastructure before running automate-notifyer or chat-notifyer.
openclaw skills install @whatsable/agent-skills-by-notifyerScripts for managing a Notifyer account via the Console API
(https://api.insightssystem.com). All Console API requests authenticate with
Authorization: Bearer <token>.
cd skills/setup-notifyer
npm install # no dependencies required yet (uses built-in fetch)
Set environment variables:
export NOTIFYER_API_BASE_URL="https://api.insightssystem.com"
export NOTIFYER_API_TOKEN="<jwt-token>" # from login.js
node scripts/create-account.js \
--name "Jane Smith" \
--email jane@company.com \
--password "Secure@123" \
--phone 14155550123
--reason is optional (shown as "(optional)" in the signup UI). Supply it to help the support team understand the use case.
Returns { ok: true, data: { authToken, user, apiKey } } on success.
The authToken can be used immediately as NOTIFYER_API_TOKEN.
node scripts/login.js \
--email jane@company.com \
--password "Secure@123"
Returns { ok: true, data: { authToken } }.
export NOTIFYER_API_TOKEN="<authToken from above>"
node scripts/get-me.js
Returns { ok: true, data: { id, name, email, role, phone_number, ... } }.
node scripts/doctor.js
node scripts/doctor.js --pretty # human-readable pass/fail report to stderr
Validates all four prerequisites in one command:
NOTIFYER_API_BASE_URL — set and starts with https://NOTIFYER_API_TOKEN) — valid and accepted by /auth/meisConnected: true (and detects degraded Meta states)active, trialing, or new_userReturns { ok: true, data: { all_healthy: true, checks: { base_url, token, connection, plan } } }.
Returns { ok: false, ... } (exit 1) if any check fails, with a fix hint for each failure.
Run doctor.js before any other script when troubleshooting unexpected failures.
node scripts/get-connection-status.js
node scripts/get-connection-status.js --pretty # human-readable summary to stderr
Returns { ok: true, data: { isConnected, degraded, meta_errors, has_embedded_user, registration, subscription, payment_method_added, is_template_has, is_message_tested, is_profile_picture_added, onboarding_steps_completed } }.
isConnected = true means the phone number has both successful Meta registration and
subscription — it is ready to send messages.
degraded = true means isConnected is true but Meta returned hidden errors inside
the whatsapp_response payload (e.g. two-step PIN mismatch, account restricted). Always
check degraded alongside isConnected — a degraded connection may fail silently.
meta_errors contains the extracted error details as a string array.
Use this when get-connection-status.js shows a failed or stale registration/subscription,
or after connecting a new number in the console.
node scripts/refresh-connection.js
node scripts/refresh-connection.js --pretty
Returns the same shape as get-connection-status.js.
Daily limit warning: Meta limits how many times per day re-registration can be attempted. If the response indicates a limit error, wait 24 hours before retrying.
node scripts/list-plans.js # all plans
node scripts/list-plans.js --billing monthly # monthly only
node scripts/list-plans.js --billing annual # annual only
node scripts/list-plans.js --tier pro # Pro tier only
node scripts/list-plans.js --tier basic --billing monthly
node scripts/list-plans.js --pretty # human-readable table to stderr
Returns all plan tiers grouped by { monthly: { basic, pro, agency }, annual: { ... } }.
Each tier entry contains id, price (in dollars), unique_numbers (contact limit),
stripe_price_id, and What_it_includes.
Plans: basic = Bulk Message (no integrations/bots), pro = full features,
agency = Pro + multiple phone numbers.
node scripts/get-user-plan.js
node scripts/get-user-plan.js --pretty
Returns { usages, latest_plan: { status, plan_amount, unique_number_limit, total_unique_number_count, end_time, ... } }.
plan_amount is in cents — the script adds a plan_amount_dollars convenience field.
node scripts/list-members.js # all members
node scripts/list-members.js --page 1 --per-page 25 # paginate
node scripts/list-members.js --labels # also show available label names
node scripts/list-members.js --pretty # human-readable table to stderr
Returns { items: TeamMember[], team_seat: { included_seats } }.
Members are sorted by role (Super Admin → Admin → Team Member (All Labels) → Team Member).
node scripts/invite-member.js \
--name "Jane Smith" \
--email jane@company.com \
--password "Secure@2024" \
--role "Team Member" \
--labels "Sales,Support"
Creates a full account immediately (no email invite flow). Share credentials out-of-band.
Assignable roles: Admin, Team Member (All Labels), Team Member.
Labels (comma-separated) are only used for Team Member role — Admin roles get all labels automatically.
# Promote to Admin
node scripts/update-member.js --id <id> --role Admin
# Assign new labels (replaces current list)
node scripts/update-member.js --id <id> --labels "Sales,VIP"
# Clear all labels
node scripts/update-member.js --id <id> --labels ""
# Rename + reset password
node scripts/update-member.js --id <id> --name "John Doe" --password "NewPass@99"
There is no separate change-role endpoint — role, labels, name and password are all
updated through the same PATCH /api:-4GSCDHb/auth/user call. The script auto-fetches
current values and only changes what you supply.
node scripts/remove-member.js --id <id> --confirm
Permanent and immediate. --confirm is required to prevent accidental deletion.
Super Admin (account owner) cannot be removed.
node scripts/list-labels.js
node scripts/list-labels.js --pretty # human-readable table to stderr
Returns { labels: Label[], count: n }.
Each label has id, label (display name), keywords (auto-assignment triggers),
user_id, and created_at.
Super Admin and Admin see all workspace labels. Team Members see only the labels assigned to their account.
node scripts/create-label.js --label "Sales"
node scripts/create-label.js --label "Support" --keywords "help,issue,ticket"
Label names must be unique. keywords are comma-separated trigger words that
auto-assign the label when a contact message contains a match.
# Add keywords
node scripts/update-label-keywords.js --id 5 --add "urgent,priority"
# Remove a keyword
node scripts/update-label-keywords.js --id 5 --remove "old-keyword"
# Replace the entire keyword list
node scripts/update-label-keywords.js --id 5 --set "buy,purchase,order"
# Clear all keywords
node scripts/update-label-keywords.js --id 5 --set ""
# Rename a label
node scripts/update-label-keywords.js --id 5 --label "VIP Customers"
--add, --remove, and --set are mutually exclusive. The script fetches the
current label first so unchanged fields are preserved.
node scripts/delete-label.js --id 5 --confirm
Permanent and immediate. --confirm is required to prevent accidental deletion.
After deletion, manually remove the label from any team members that had it
assigned using update-member.js --labels.
node scripts/get-api-key.js
node scripts/get-api-key.js --pretty # prints key to stderr for easy copying
Returns { id, api_key, user_id, created_at }.
The api_key value is the credential used by Make, Zapier, n8n, and custom scripts
to send messages via the developer API. It authenticates as a raw Authorization
header (no Bearer prefix) — different from NOTIFYER_API_TOKEN.
Bearer <jwt>), Chat (<jwt> raw), Developer
(<api_key> raw). The console JWT and the Developer API key are different credentials.
get-api-key.js uses console auth to retrieve the key; the key itself is then used
by external tools as a raw Authorization header.get-user-plan.js before directing a user to set up integrations.api_key
as a long-lived secret; store it in env vars, never in source control.send_template_message_by_api uses the API key, not the JWT — when calling
POST /api:hFrjh8a1/send_template_message_by_api, set
Authorization: <api_key> (no Bearer). phone_number is passed as text here
(unlike console APIs where it is an integer).sub_channel: "onboarding_test" is a special mode that updates embedded_users
and is only for test sends. Omit sub_channel (or pass "") for production sends.list-labels.js, create-label.js,
update-label-keywords.js, and delete-label.js all use
Authorization: <token> (no Bearer prefix). The same NOTIFYER_API_TOKEN
from login.js works — notifyer-api.js handles the format difference via
AUTH_MODE_CHAT.create-label.js returns
{ ok: false, blocked: true } if a label with the same name already exists.keywords is a full replacement — update-label-keywords.js --set replaces
the entire list. Use --add / --remove to make incremental changes.update-label-keywords.js and
delete-label.js both call GET /web/label_management to look up the target by
id before mutating.{ deleted: true, id, label } from the pre-flight fetch.delete-label.js,
update affected team members manually with update-member.js --labels.phone_number must be a number — send as integer (e.g. 14155550123),
not a string. Xano types this field as integer.@!#$%^&*).Origin header is injected automatically. notifyer-api.js adds
Origin: https://console.notifyer-systems.com for console-mode requests and
Origin: https://chat.notifyer-systems.com for chat-mode requests. You never need
to pass it manually. If a script sets Origin via extraHeaders, that value
takes precedence. This fixes a class of silent 401s that occurred when the header
was missing on Xano endpoints that validate it.authToken in NOTIFYER_API_TOKEN. Never commit
tokens to source control.{ ok: false, error: "..." }.invite-member.js creates the account directly.
Share credentials with the new member out-of-band. There is no "pending invite" state.update-member.js fetches current state first — you only need to supply the fields
you want to change; unchanged fields are read from the existing member and re-sent.labels replaces, not appends — update-member.js --labels "Sales" sets labels
to exactly ["Sales"], removing any previous ones.update-member.js sends labels: []
automatically when the effective role is not Team Member.plan_amount is in cents — latest_plan.plan_amount is in cents (Stripe convention).
get-user-plan.js adds a plan_amount_dollars field for convenience.POST /api:Mk_r6mq0/sessions creates a Stripe
checkout session that requires a browser redirect. Agents cannot subscribe on behalf
of a user — direct them to https://console.notifyer-systems.com/pricing-plans.status ∈ ["active","trialing"] and usages < unique_number_limit.get-connection-status.js returns the status of that single number.isConnected vs has_embedded_user — has_embedded_user means a Meta
Facebook account has been linked. isConnected (registration.success && subscription.success) means WhatsApp messaging is actually ready. Always
check isConnected before sending messages.refresh-connection.js re-triggers Meta
registration. Meta rate-limits this per day. If you see a daily limit error,
wait 24 hours.Notifyer's backend uses Xano-style API group IDs in the URL path:
| Group | Prefix | Used for |
|---|---|---|
| Auth | /api:-4GSCDHb | Signup, login, get-me, api_key, team member CRUD |
| Message Sending | /api:hFrjh8a1 | Send template messages via Developer API key |
| WhatsApp Connection | /api:P5grzx1u | Connection status, Meta re-registration |
| Web/Console | /api:bVXsw_FD | Label CRUD (/web/label_management), recipients, team |
| Roles | /api:eWoClqoZ | Get available label names for member assignment |
| Plans | /api:JZAUyiCs | Plan listing and selection |
| File | Description |
|---|---|
scripts/lib/notifyer-api.js | Base HTTP client — loads config, sends requests, handles errors |
scripts/lib/args.js | CLI argument parser (flags, booleans, numbers) |
scripts/lib/result.js | Standard output helpers — ok(), err(), printJson() |
scripts/create-account.js | POST /api:-4GSCDHb/auth/signup — create a new Notifyer account |
scripts/login.js | POST /api:-4GSCDHb/auth/login — login and get an auth token |
scripts/get-me.js | GET /api:-4GSCDHb/auth/me — get the authenticated user's profile |
scripts/get-connection-status.js | GET /api:P5grzx1u/is_user_embedded — WhatsApp connection status |
scripts/refresh-connection.js | POST /api:P5grzx1u/refresher_of_registration_subscription — force re-sync with Meta |
scripts/list-plans.js | GET /api:JZAUyiCs/plans?filter=… — list available subscription plan tiers |
scripts/get-user-plan.js | GET /api:JZAUyiCs/user_plan — current subscription and usage |
scripts/list-members.js | GET /api:-4GSCDHb/auth/get_team_member — list team members; --labels also fetches available label names |
scripts/invite-member.js | POST /api:-4GSCDHb/auth/create_team_member — create a team member account |
scripts/update-member.js | PATCH /api:-4GSCDHb/auth/user — update role, labels, name, or password |
scripts/remove-member.js | DELETE /api:-4GSCDHb/auth/delete_team_member/:id — permanently remove a member |
scripts/list-labels.js | GET /api:bVXsw_FD/web/label_management — list workspace labels (role-filtered) |
scripts/create-label.js | POST /api:bVXsw_FD/web/label_management — create a new label |
scripts/update-label-keywords.js | PATCH /api:bVXsw_FD/web/label_management/:id — update name or keywords (fetch-then-patch) |
scripts/delete-label.js | DELETE /api:bVXsw_FD/web/label_management/:id — permanently delete a label |
scripts/get-api-key.js | GET /api:-4GSCDHb/api_key — retrieve the Developer API key for Make/Zapier/n8n |
scripts/doctor.js | Pre-flight health check — validates base URL, token, WhatsApp connection, and plan status in one command |
references/account-reference.md — Full API reference for auth endpoints, field types, error codes, and token usagereferences/whatsapp-connection-reference.md — Connection status fields, onboarding checklist, rate limits, and architecture notesreferences/plans-reference.md — Plan filters, PricingTier shape, LatestPlan fields, status values, billing modelreferences/team-reference.md — Role system, team member CRUD endpoints, label assignment rules, common workflowsreferences/labels-reference.md — Label data model, all CRUD endpoints, keyword auto-assignment behaviour, role-filtering rulesreferences/api-key-reference.md — Developer API key retrieval, all three auth modes, and send_template_message_by_api reference for Make/Zapier/n8nassets/signup-example.json — Example signup request payloadassets/connection-status-example.json — Example connection status responseassets/user-plan-example.json — Example response from get-user-plan.jsNOTIFYER_API_BASE_URL must be https://. All three skills enforce this at startup — any http:// or non-HTTPS URL is rejected immediately to prevent tokens being sent unencrypted or to a rogue host.--password is visible in the OS process list. CLI flags are readable via ps aux or /proc/<pid>/cmdline for the lifetime of the process. On shared or monitored machines, prefer injecting credentials via environment variables or a secrets manager rather than bare CLI flags.login.js is printed to stdout. This is by design — the agent must capture it to export NOTIFYER_API_TOKEN. In orchestrated environments, ensure stdout is not persisted to unprotected logs. Treat the token like a session cookie.get-api-key.js is printed to both stdout and stderr. Store it immediately in a secrets manager. It provides direct WhatsApp send access without a session login.get-connection-status.js and refresh-connection.js can manage the connection programmatically.PATCH /api:0hqyGRIz/whatsapp_verification/{userId} endpoint (OTP submission during phone re-authentication) is triggered by the console UI. There is no script for this flow.create-account.js creates a full Notifyer workspace. There is no delete-account endpoint.GET /reset_password?email= to trigger email + PATCH /reset_password to set the new password) requires the user to click a link in the email. There is no agent-accessible reset path that bypasses the email step.refresh-connection.js re-syncs an existing connection. It cannot re-initiate a fully disconnected or revoked WABA — that requires going through the browser-based embedded signup again.list-plans.js and get-user-plan.js are read-only. Changing plans (POST /api:Mk_r6mq0/sessions), accessing the billing portal (POST /api:Mk_r6mq0/portal), and buying credits (POST /api:Mk_r6mq0/add_credits) are Stripe redirect flows — not scriptable.PATCH /profile_picture_update, PATCH /payment_method_update, and PATCH /test_message_update are completion flags set by the console onboarding UI. There are no scripts for these — they do not affect core messaging functionality once the account is set up.update-member.js. Super Admin is set by Notifyer at workspace creation.[setup-notifyer file map]|root: .
|.:{package.json,SKILL.md}
|assets:{connection-status-example.json,signup-example.json,user-plan-example.json}
|references:{account-reference.md,api-key-reference.md,labels-reference.md,plans-reference.md,team-reference.md,whatsapp-connection-reference.md}
|scripts:{create-account.js,create-label.js,delete-label.js,doctor.js,get-api-key.js,get-connection-status.js,get-me.js,get-user-plan.js,invite-member.js,list-labels.js,list-members.js,list-plans.js,login.js,refresh-connection.js,remove-member.js,update-label-keywords.js,update-member.js}
|scripts/lib:{args.js,notifyer-api.js,result.js}