Skip to content
chat-notifyer logo

Chat Notifyer

chat-notifyer

Live chat operations for Notifyer by WhatsAble. Enables AI agents to operate the WhatsApp chat interface: list and search conversations, send text/template/ attachment messages, assign labels, control AI bot vs. human handoff, schedule messages, and manage recipient notes. Use this skill when you...

SKILL.md

Full skill instructions

chat-notifyer

Live chat operations for the Notifyer platform (chat.notifyer-systems.com).

This skill covers Phase 3 of the Notifyer agent-skills suite:

PhaseSkillCoverage
1setup-notifyerAccount, WhatsApp connection, Plans, Team, Labels, API Key
2automate-notifyerTemplates, AI Bots, Broadcasts, Analytics, Webhooks
3chat-notifyerRecipients, Messaging, Labels, Handoff, Scheduling, Notes

Environment Variables

Set these before running any script:

VariableRequiredDefaultDescription
NOTIFYER_API_BASE_URLyes—Backend API base URL (e.g. https://api.insightssystem.com)
NOTIFYER_API_TOKENyes—JWT token from setup-notifyer/​login.js
NOTIFYER_CHAT_ORIGINnohttps://chat.notifyer-systems.comCORS Origin header for chat endpoints
export NOTIFYER_API_BASE_URL="https://api.insightssystem.com"
export NOTIFYER_API_TOKEN="eyJhbGciOi..."     # from setup-notifyer/​login.js

Authentication

This skill uses Chat Auth Mode: Authorization: <token> (raw JWT, NO Bearer prefix).

This is different from setup-notifyer and automate-notifyer which use Authorization: Bearer <token>.

The same JWT token works for both modes — only the header format differs.

The token is obtained from setup-notifyer/​scripts/​login.js and stored as NOTIFYER_API_TOKEN.


CORS

Several endpoints run Xano's /​cors_origin_web_chat function which allows requests from:

  • https://chat.notifyer-systems.com (primary)
  • https://console.notifyer-systems.com
  • https://api.insightssystem.com
  • https://preview-chat-notifyer.vercel.app
  • http://localhost:5173, http://localhost:3000, http://127.0.0.1:5173

Scripts automatically send Origin: https://chat.notifyer-systems.com.
Optional: set NOTIFYER_CHAT_ORIGIN if you need a different Origin header.

Endpoints that do NOT require CORS: /​chatapp/​* endpoints, send/​text.


API Group IDs

GroupPath PrefixCovers
Auth/​api:-4GSCDHb/​auth/​me — resolves user_id for chatapp endpoints
Chat Web/​api:bVXsw_FDRecipients, messaging, schedules (primary group for this skill)
Media Upload/​api:ox_LN9zXFile upload for attachments
AI Config/​api:Sc_sezERList bots (console auth)

24-Hour Window Rule

WhatsApp policy: Free-text messages and attachments can only be sent within 24 hours of the recipient's last inbound message.

Window open:   recipient.expiration_timestamp > Date.now()
Window closed: recipient.expiration_timestamp == null OR < Date.now()
Window StateAllowed Messages
OpenText ✓, Template ✓, Attachment ✓
ClosedTemplate only ✓

Before sending text or attachments, verify the 24-hour window:

node scripts/​get-recipient.js --phone 14155550123 --pretty

How-to Guide

List all active conversations

node scripts/​list-recipients.js --pretty

Search for a specific contact

node scripts/​list-recipients.js --search "John" --pretty
node scripts/​list-recipients.js --search "14155550123" --pretty

Get full recipient details (with 24h window check)

node scripts/​get-recipient.js --phone 14155550123 --pretty

List unread conversations with a specific label

node scripts/​filter-recipients-by-label.js --labels "Support" --status unread --pretty

Label matching is case-sensitive. If the API returns 0 results, the script automatically retries with case-insensitive client-side filtering and flags used_case_insensitive_fallback: true in the output.

Fetch all recipients across all pages

node scripts/​list-recipients.js --all --pretty

Send a text message

node scripts/​send-text.js --phone 14155550123 --text "Hello! How can I help?"

send-text.js automatically checks the 24h messaging window before sending. If the window is closed it exits with ok: false and a clear message explaining the options (use a template, or wait for the contact to message first). No manual pre-check with get-recipient.js is needed.

Send a template message (works any time)

# By template name (recommended — easier than looking up the ID):
node scripts/​send-template.js --phone 14155550123 --name order_confirm
node scripts/​send-template.js --phone 14155550123 --name order_confirm \
  --variables '{"body1":"John","body2":"#12345"}'

# List all available templates:
node scripts/​send-template.js --list

# Preview what would be sent without actually sending:
node scripts/​send-template.js --phone 14155550123 --name order_confirm --dry-run

# By template ID (legacy):
node scripts/​send-template.js --phone 14155550123 --template tmpl_abc123

Send a file (image, PDF, video, audio)

# Single file — no caption
node scripts/​send-attachment.js --phone 14155550123 --file /​path/​to/​invoice.pdf --pretty

# Single file — with caption
node scripts/​send-attachment.js --phone 14155550123 --file /​path/​to/​photo.jpg --caption "Your order photo"

# Multiple files — shared caption for all
node scripts/​send-attachment.js --phone 14155550123 \
  --files "/​path/​to/​photo.jpg,/​path/​to/​invoice.pdf,/​path/​to/​video.mp4" \
  --caption "See the attached files" --pretty

# Multiple files — per-file captions (JSON array, positional)
node scripts/​send-attachment.js --phone 14155550123 \
  --files "/​path/​to/​photo.jpg,/​path/​to/​invoice.pdf,/​path/​to/​video.mp4" \
  --captions '["Great photo","Your invoice",""]'

# Mixed — per-file captions with a fallback for unspecified positions
node scripts/​send-attachment.js --phone 14155550123 \
  --files "/​path/​to/​photo.jpg,/​path/​to/​invoice.pdf,/​path/​to/​video.mp4" \
  --captions '["Great photo"]' \
  --caption "See attached"

Files are uploaded 3 at a time concurrently, then sent sequentially. Max 10 files per call.

--captions is a JSON string array — one entry per file by position. Use "" for no caption on a specific file. If the array is shorter than the file list, remaining files use --caption (or no caption if --caption is also omitted). --caption and --captions can be combined.

Schedule a message for later

node scripts/​send-text.js \
  --phone 14155550123 \
  --text "Your appointment is tomorrow at 10am!" \
  --schedule "25/​01/​2025 09:00"

node scripts/​send-template.js \
  --phone 14155550123 \
  --template tmpl_abc123 \
  --schedule "25/​01/​2025 14:00"

View all scheduled messages

node scripts/​list-scheduled.js --pretty
node scripts/​list-scheduled.js --phone 14155550123

Cancel a scheduled message

node scripts/​delete-scheduled.js --id 7 --confirm

Assign a label to a conversation

node scripts/​assign-label.js --phone 14155550123 --label "Support" --pretty

Labels must exist — create them first via setup-notifyer/​create-label.js.

Remove a label from a conversation

node scripts/​remove-label.js --phone 14155550123 --label "Support" --pretty

Filter conversations by label

node scripts/​filter-recipients-by-label.js --labels "VIP,Support" --pretty

Human handover — when a contact asks to speak to a human agent

This is the primary escalation workflow. Use it whenever the contact expresses a desire to speak with a human — even implicitly (e.g. "I need help", "can someone call me", "talk to a person", "agent please", "representative").

The correct method is to assign the bot's handoff_label to the conversation. Notifyer automatically sets is_ai_assistant = false when this label is assigned, stopping the bot and routing the conversation to human agents in one step.

# Step 1 — confirm the bot's configured handoff label (do this once; remember the value)
node ../​automate-notifyer/​scripts/​list-bots.js --pretty
# Look for: handoff_label — e.g. "Human"

# Step 2 — assign the handoff label (this stops the bot AND routes to humans)
node scripts/​assign-label.js --phone 14155550123 --label "Human" --pretty

What happens automatically after Step 2:

  • Notifyer detects label = handoff_label on the recipient
  • Sets is_ai_assistant = false — bot stops responding immediately
  • Conversation appears in the queue for Team Members scoped to the "Human" label
  • Human agents see it in their filtered conversation list in the chat app

Do NOT call set-handoff.js separately — the label assignment already triggers the handoff. Calling both would be redundant.

If the handoff_label is not configured on the bot, fall back to:

# Fallback — manual handoff without label routing
node scripts/​set-handoff.js --phone 14155550123 --mode human --pretty

This stops the bot but does not route to a label-scoped agent queue.


Agent guidance — detecting human request intent

When running as an AI bot in a conversation, monitor for these signals and trigger the human handover workflow above:

  • Explicit: "I want to speak to a human", "talk to an agent", "give me a person", "connect me to support", "I need a representative", "human please"
  • Implicit: "this isn't helping", "you don't understand", "I need real help", "call me", "this is urgent", "I want to escalate"
  • Repeated failures: if the bot has failed to resolve the issue after 3 attempts, proactively offer handover

Before escalating, optionally send an acknowledgement message:

node scripts/​send-text.js --phone 14155550123 \
  --message "I'm connecting you with a human agent now. Someone will be with you shortly."

Then immediately assign the handoff label.


Take over a conversation from the AI bot (manual — human-initiated)

node scripts/​set-handoff.js --phone 14155550123 --mode human --pretty

Return a conversation to the AI bot

node scripts/​set-handoff.js --phone 14155550123 --mode bot --pretty

Assign a specific AI bot to a conversation

# Step 1: list available bots
node scripts/​list-bots.js --pretty

# Step 2: assign bot and enable AI mode
node scripts/​assign-bot.js --phone 14155550123 --bot-id 5 --pretty

Read the full conversation thread (sent + received)

# Last 30 messages (both sides of the conversation):
node scripts/​get-conversation.js --phone 14155550123 --pretty

# Page through history:
node scripts/​get-conversation.js --phone 14155550123 --page 1 --per-page 50 --pretty

Read outbound send history (analytics/​delivery log)

# Last 20 outbound-only messages with delivery status:
node scripts/​get-conversation-log.js --phone 14155550123 --pretty

# All messages ever sent to this contact:
node scripts/​get-conversation-log.js --phone 14155550123 --all --pretty

Note: get-conversation.js returns the full bidirectional thread (both sides). get-conversation-log.js returns outbound-only sends with delivery analytics (from the console log API).

Update a recipient's display name

node scripts/​update-recipient.js --phone 14155550123 --name "John Doe" --pretty

Read notes for a recipient

node scripts/​get-notes.js --phone 14155550123 --pretty

Add or update a manual note

node scripts/​add-note.js --phone 14155550123 --note "VIP customer — apply 15% discount"
node scripts/​add-note.js --phone 14155550123 --append "Requested callback on 15 Feb"
node scripts/​add-note.js --phone 14155550123 --note ""   # clear note

Feedback

If you encounter an error, find something unclear, want to request a feature, or spot a security concern while using this skill, send feedback to the Notifyer team:

node ../​setup-notifyer/​scripts/​send-feedback.js \
  --feedback "your message here" \
  --type error|request|unclear|security|improvement|general \
  --skill chat-notifyer \
  --script <script-name.js>

Requires NOTIFYER_API_TOKEN (same token used by all scripts).


Rules for AI Agents

  1. Auth mode: Use raw JWT (Authorization: <token>, no Bearer prefix) for all chat endpoints in this skill, except list-bots.js, which uses console auth.

  2. Phone numbers: Send phone numbers as integers (no + prefix). Parse with parseInt(phone.replace(/^\+/, ""), 10).

  3. 24h window: send-text.js auto-checks the window and refuses to send if it is closed — no pre-check needed. For attachments, check expiration_timestamp via get-recipient.js. If window closed, use send-template.js.

  4. Fetch before patch: For label changes, note changes, and bot assignment — fetch the recipient first to get current state, then PATCH with the full intended state.

  5. Labels are strings: global_label is a string[] of label names (not IDs). Send ["Support", "Billing"] — not [1, 2].

  6. CORS endpoints: All /​web/​* endpoints require Origin: https://chat.notifyer-systems.com. Scripts handle this automatically.

  7. user_id for chatapp endpoints: get-recipient.js and set-handoff.js call /​auth/​me internally to resolve the user_id UUID. No manual action needed.

  8. Page numbering: Xano uses 0-based page numbers internally. Scripts expose 1-based page numbers to users (--page 1 = page_number=0 in API).

  9. Template scheduling: scheduled_time: 0 = immediate send. 0 is NOT a null/​empty — it is the explicit "immediate" signal.

  10. list-bots.js uses console auth: This is intentional — the AI config endpoint is in the console API group. Both Bearer and raw token use the same JWT, just different formats.

  11. Human handover = assign the handoff_label, not set-handoff.js: When a contact requests a human, use assign-label.js --label "<handoff_label>". This assigns the label AND automatically flips is_ai_assistant = false in one step. Calling set-handoff.js alone stops the bot but does NOT route the conversation into the human agent's label queue. Always prefer the label-based path. If handoff_label is unknown, run list-bots.js once to retrieve it.

  12. Proactive handover: If the bot has failed to resolve the contact's issue after 3 attempts, or if the contact repeats the same question more than twice, proactively offer a human handover without waiting to be asked explicitly.


Scripts (FILE MAP)

ScriptDescriptionAuth Mode
scripts/​list-recipients.jsList/​search conversation recipients with paginationChat
scripts/​get-recipient.jsGet single recipient by phone numberChat
scripts/​filter-recipients-by-label.jsList recipients filtered by label(s)Chat
scripts/​send-text.jsSend a free-text message (auto-checks 24h window; refuses if closed)Chat
scripts/​send-template.jsSend a template message (no window required; supports --name, --list, --dry-run)Chat
scripts/​send-attachment.jsUpload 1–10 files then send as image/​video/​audio/​document (auto-detects type per file; concurrent upload, sequential send)Chat
scripts/​assign-label.jsAssign a label to a recipientChat
scripts/​remove-label.jsRemove a label from a recipientChat
scripts/​set-handoff.jsToggle AI bot vs. human modeChat
scripts/​assign-bot.jsAssign specific AI bot to recipientChat
scripts/​list-bots.jsList all AI bots (for bot ID lookup)Console
scripts/​list-scheduled.jsList all scheduled messagesChat
scripts/​delete-scheduled.jsCancel a scheduled messageChat
scripts/​add-note.jsSet or append to manual note on recipientChat
scripts/​get-notes.jsRead manual + AI-generated notes for recipientChat
scripts/​get-conversation.jsRead full bidirectional chat thread (sent + received messages)Chat
scripts/​get-conversation-log.jsRead outbound-only send history with delivery status (console log API)Console
scripts/​update-recipient.jsUpdate recipient display nameChat

Shared Library (scripts/​lib/)

FileDescription
lib/​notifyer-api.jsloadConfig, requestJson, AUTH_MODE_CHAT, AUTH_MODE_CONSOLE
lib/​args.jsparseArgs, getFlag, getBooleanFlag, getNumberFlag
lib/​result.jsok, err, printJson — standardised JSON output
lib/​schedule-response.jsvalidateScheduledSendResponse — detects silent schedule failures (status: not_passed, id: null)

References

FileCoverage
../​../​AUTHENTICATION.mdAll three auth surfaces — curl examples, decision guide, header formats, error diagnostics
references/​recipients-reference.mdRecipient object, GET/​PATCH endpoints, 24h window, label routing
references/​messaging-reference.mdText, template, attachment send APIs — all parameters and side effects
references/​labels-handoff-reference.mdLabel assignment, keyword auto-labelling, handoff modes, bot assignment
references/​scheduling-notes-reference.mdScheduled messages, chat_schedule table, note fields

Assets

FileDescription
assets/​send-template-example.jsonExample --variables payloads for common template patterns

Limitations

  • WhatsApp connection must exist before any messaging. If the WhatsApp number is disconnected, all send scripts will fail. Check with setup-notifyer/​get-connection-status.js. Re-connecting a fully revoked WABA requires the browser-based embedded signup — it cannot be scripted.
  • get-conversation.js reads the full thread; get-conversation-log.js is outbound-only. Use get-conversation.js (Chat API, /​web/​conversations) to read both sides of a conversation. Use get-conversation-log.js (Console API, /​api:ereqLKj6/​log) for outbound delivery analytics only.
  • No incoming message handling in scripts. Incoming messages trigger webhooks (see automate-notifyer skill). Scripts cannot subscribe to or poll for new inbound messages.
  • 24h window is enforced by WhatsApp server-side. Scripts cannot bypass it. When the window is closed, use send-template.js — free-text sends will be rejected by Meta.
  • note_auto is read-only. AI-generated notes are written by Notifyer's internal AI logic and cannot be set or cleared via API.
  • No bulk send from chat. For bulk messaging to multiple recipients at once, use automate-notifyer/​create-broadcast.js.
  • Template approval required before use. Templates must have APPROVED status from Meta. Manage template creation and status via automate-notifyer/​create-template.js and list-templates.js.
  • Team Member token restricts recipient visibility. Xano server-side filters recipients to the member's assigned label scope. This cannot be overridden from the script.
  • set-handoff.js and get-recipient.js call /​auth/​me internally. This adds one extra API round-trip on each invocation. If the token is expired, both the auth/​me call and the main call will fail — re-run setup-notifyer/​login.js to refresh.
  • Mark-as-read has no script. PATCH /​api:bVXsw_FD/​web/​conversations ({ phone_number, message_id, status }) updates message read/​delivery status. This is triggered automatically by the chat UI when a conversation is opened — there is no script for it, and AI agents do not need to call it manually.
  • Recipient CSV download is not covered. GET /​api:bVXsw_FD/​recipient_download_csv returns a binary CSV stream. Use raw fetch with response.text() or response.blob() in a custom workflow if you need to export the full recipient list.

More Security skills

supabase logo
Security

supabase

Handles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...

2.7K 308.9K
View

Comprehensive guides and best practices for Neon Serverless Postgres, covering setup, connection methods, authentication, and platform APIs.

98 216.2K
View

Guide for setting up and using Firebase Authentication. Use this skill when the user's app requires user sign-in, user management, or secure data access using auth rules.

462 163.8K
View

A skill to evaluate how secure Firestore security rules are. Use this when Firestore security rules are updated to ensure that the generated rules are extremely secure and robust.

462 127.7K
View

Official skill for integrating Firebase AI Logic (Gemini API) into web applications. Covers setup, multimodal inference, structured output, and security.

462 125.1K
View

Complete Better Auth server and client setup with database adapters, session management, plugins, and security configuration.

222 118.2K
View

Deploy and manage projects on Vercel using token-based authentication. Use when working with Vercel CLI using access tokens rather than interactive login — e.g. "deploy to vercel", "set up vercel", "add environment variables to vercel".

31.9K 116.1K
View
cloudflare logo
Security

cloudflare

Complete Cloudflare platform integration with decision trees for compute, storage, AI, networking, security, and infrastructure-as-code.

3K 110.7K
View

Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.

253 103K
View
gws-gmail logo
Security

gws-gmail

Send, read, and manage Gmail messages, drafts, labels, and account settings.

31.2K 78.9K
View

Comprehensive website auditing across 230+ rules in 21 categories including SEO, performance, security, and accessibility.

94 72.3K
View
gws-shared logo
Security

gws-shared

Shared authentication, CLI syntax, and output formatting patterns for gws Google Workspace commands.

31.2K 63.4K
View

Security AI tools

StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
GeoSpy logo
Security

GeoSpy

GeoSpy: Pricing, Features, FAQs, and Alternatives for AI Teams

Free
View

Detect AI-generated voices to protect against audio fraud.

Paid
View

Ensure Your Content's Originality with AI Plagiarism Checker

Freemium
View
Img Upscaler logo
Security

Img Upscaler

Upscale images by 400% without quality loss

Freemium
View
AICheatCheck logo
Security

AICheatCheck

Accurately Detect AI-Generated Content with TheChecker.AI

Free
View
D
Security

Detect GPT

Chrome extension that detects and flags AI-generated content

Free
View