Package Information
Available Nodes
Documentation generating…
Documentation
n8n-nodes-befroosh
Custom n8n nodes for Befroosh. This package is the home for any n8n node we build.
It ships the Befroosh SMS node, plus the analytics-webhook pair — Befroosh Analytics
Trigger and Befroosh Replay — driven by a shared Befroosh Analytics API credential.
Layout
apps/n8n-nodes/
├── credentials/
│ ├── NotrikaSmsApi.credentials.ts # one per SMS provider
│ ├── BatabjamSmsApi.credentials.ts
│ ├── MeliPayamakSmsApi.credentials.ts
│ ├── BatabjamAboardSmsApi.credentials.ts
│ ├── BefrooshAnalyticsApi.credentials.ts # baseUrl + signingSecret + apiKey
│ └── BefrooshEmailApi.credentials.ts # SMTP host/port/user/pass/fromAddress (mirrors core)
├── lib/
│ └── signature.ts # local HMAC verify (self-contained) + tests
├── nodes/
│ ├── BefrooshSms/
│ ├── BefrooshAnalyticsTrigger/ # webhook trigger (verifies + emits events)
│ ├── BefrooshReplay/ # schedule/cancel/status replay calls
│ ├── BefrooshAssignAction/ # create + assign an admin task
│ ├── BefrooshWait/ # pause on an offset schedule
│ ├── BefrooshStatus/ # route by user status (10 outputs)
│ └── BefEmailOrSms/ # subscription-alert via email or SMS
├── scripts/copy-icons.mjs # copies .svg/.png into dist after tsc
├── tsconfig.json
└── package.json # the "n8n" field registers nodes + credentials
Self-contained (CLAUDE.md §10): this package is published, so it imports no
@befroosh/*/workspace:*code.lib/signature.tsre-implements the webhook
signature scheme locally (mirrorsapps/core/.../webhook-signer.ts); tests run with
Node's built-in runner:node --test lib/signature.test.ts.
Develop
pnpm --filter n8n-nodes-befroosh build # tsc → dist + icons
pnpm --filter n8n-nodes-befroosh check-types # type-check only
pnpm --filter n8n-nodes-befroosh dev # tsc --watch
Add another node
- Create
nodes/<MyNode>/<MyNode>.node.tsexporting a class that implementsINodeType
(and an icon next to it). - If it needs secrets, add
credentials/<MyApi>.credentials.tsimplementingICredentialType. - Register both in the
"n8n"field ofpackage.json(point at the compileddist/...js). pnpm --filter n8n-nodes-befroosh build.
Befroosh SMS node
One node, Provider dropdown selects which backend SMS service to use. Each provider has
its own credential (shown only when that provider is selected). Request shapes mirrorapps/core/src/providers/sms/services/*:
| Provider | Endpoint | Auth | Operations |
|---|---|---|---|
| Notrika | POST api.notrikaco.ir/api/v1/messages/send/template |
X-Api-Key |
Send Message, Send OTP |
| Batabjam | POST smsapi.pishgamrayan.com/Messages/Send |
Authorization token |
Send Message |
| MeliPayamak | GET sms.toolzi.ir/post/Send.asmx/... |
username/password in query | Send Message, Send OTP |
| Batabjam Aboard | login /api/login.php → POST /api/send-bulk-sms.php |
bearer (from login) | Send Message, Send OTP |
Fields: To (Batabjam/Aboard accept comma-separated numbers), Message (Send Message)
or OTP Code (Send OTP). Set the node to Continue On Fail if a send must never break a
workflow.
Befroosh Analytics API credential
One credential (befrooshAnalyticsApi) shared by the trigger and replay nodes — it
replaces the old BEFROOSH_* env vars:
| Field | Used by | Purpose |
|---|---|---|
baseUrl |
Replay | Core API base incl. version prefix, e.g. https://core/v1 |
signingSecret |
Trigger | HMAC secret to verify X-Befroosh-Signature |
apiKey |
Replay | Per-endpoint Bearer key (awh_live_…) for the Replay API |
Befroosh Analytics Trigger node
A webhook trigger that receives Befroosh analytics events and verifies them. It computesHMAC_SHA256(signingSecret, "<t>.<rawBody>") over the raw request bytes and compares it
to the t=…,v1=… X-Befroosh-Signature header, with a Tolerance (Seconds) anti-replay
window (default 300). Invalid/stale → HTTP 401, no item emitted; a missing signing secret
throws a node error (misconfiguration, not a 401). Valid → acks 200 (responseMode: onReceived)
and emits one flattened item: eventId, type, parent, occurredAt, actorUserId, workspaceId, data, context, delivery {id, attempt, origin, replayCount, replayScheduleId}, event. Route
downstream with a Switch on type.
Test the trigger without the backend
scripts/send-test-event.mjs builds a mock analytics event, signs it with the sameHMAC_SHA256(signingSecret, "<t>.<rawBody>") scheme the core dispatcher uses, and POSTs it
straight to an n8n webhook URL — so you can exercise a workflow without a registered
endpoint or the backend fan-out. The signing secret is used locally to compute the HMAC and is
never sent over the wire; supply the same secret the credential holds.
# from apps/n8n-nodes
node scripts/send-test-event.mjs \
--url https://dl4.mahsolist.ir:8443/webhook/befroosh-analytics \
--secret <signingSecret> \
--email user@example.com # and/or --mobile 09120000000
# or: npm run send-test -- --url … --secret … --email …
Options: --type (default account.created), --workspace-id, --actor-user-id, --stale
(sign an out-of-tolerance timestamp to confirm the node returns 401), --help. The
production URL is required and the workflow must be Active (the test URL only listens
while the editor is open). Self-signed host? Set NODE_EXTRA_CA_CERTS rather than disabling TLS.
Testing the Replay node (--db)
Replay re-delivers a stored event by id, so a mock that was never persisted will 404
(ANALYTICS_WEBHOOK_EVENT_NOTFOUND). Add --db <conninfo> to also INSERT the event into the
backend's analytics_event table before posting, so the workflow's Replay node can find it:
PGPASSWORD=… node scripts/send-test-event.mjs \
--url https://dl4.mahsolist.ir:8443/webhook/befroosh-analytics \
--secret <signingSecret> --email user@example.com \
--db postgresql://postgres@HOST:5440/xx_mvp
The INSERT is a local raw SQL statement run via the external psql binary (no backend import —
stays self-contained per CLAUDE.md §10); its column list mirrors migration 1781000000000 andpayload = the event's data (which is what replay rebuilds the delivered envelope from). The
endpoint must still be subscribed to the event type and the row stays within the 90-day
retention window. Note: the replayed delivery re-POSTs to the same endpoint, so design the
workflow to not replay an already-replayed event (check delivery.replayCount).
The script is plain ESM in scripts/ — tsc does not compile it and files: ["dist"] never
publishes it. npm test round-trips its output through the node's real verifySignature to
guarantee the bytes it signs are accepted.
Befroosh Replay node
An action node that calls the Replay API at {baseUrl}/analytics/replays withAuthorization: Bearer {apiKey}:
| Operation | Call | Key params |
|---|---|---|
| Schedule Replay | POST /analytics/replays |
eventId (default ={{ $json.eventId }}), schedule (default ["1d","2d","3d"]) |
| Cancel Replay | DELETE /analytics/replays/:id |
replayScheduleId (default ={{ $json.delivery.replayScheduleId }}) |
| Get Status | GET /analytics/replays/:id |
replayScheduleId |
Defaults auto-wire from an upstream Befroosh Analytics Trigger item, so the commonTrigger → Switch → Replay flow needs no manual id entry. Surfaces the backend error code
and honors Continue On Fail.
Install into an n8n instance
A custom node has to be loaded by the n8n runtime (it is not importable as a workflow):
- Self-hosted: the package is published to npm as
n8n-nodes-befroosh, so the
simplest path is Settings → Community Nodes → Install →n8n-nodes-befroosh.
Alternativelynpm i n8n-nodes-befrooshinto~/.n8n/nodes/(or build locally and drop
it under~/.n8n/custom/). Restart n8n after a manual install. - Managed/hosted (e.g. koochaa): only works if the host allows custom/community nodes.
If it doesn't, use the HTTP-Request / sub-workflow approach inBack/integrations/n8n/
instead.