n8n-nodes-iteras
v0.3.3
Published
Unofficial n8n community nodes for Iteras. Starts workflows from Iteras webhook events and reads customer data. Not affiliated with Iteras.
Maintainers
Readme
n8n-nodes-iteras
Unofficial. This is an independent community project. It is not built, endorsed, supported or reviewed by Iteras, and it has no affiliation with them. Questions about these nodes belong in this repository's issues; questions about the Iteras API itself belong with Iteras.
n8n community nodes for Iteras, the subscription management platform.
| Node | Type | What it does | | --- | --- | --- | | Iteras Trigger | Trigger | Starts a workflow when Iteras reports a customer or subscription event | | Iteras | Action | Reads customer data from the Iteras API |
The two are built to be used together: a trigger fires with a customer ID, and the Iteras node turns that ID into the customer's name, email and subscriptions.
More Iteras nodes are meant to live in this same package. See Adding events and nodes.
Installation
In a self-hosted n8n (Settings → Community nodes)
Install n8n-nodes-iteras by name. The instance needs
N8N_COMMUNITY_PACKAGES_ENABLED=true, which is the default. n8n checks new
packages against its vetted list, so you will be asked to confirm that you
understand the risk of installing an unverified one.
Locally, without publishing
npm install
npm run build
npm link # in this folder
cd ~/.n8n/custom && npm link n8n-nodes-iterasRestart n8n. ~/.n8n/custom may need npm init -y the first time.
While developing
npm run devStarts n8n with this package linked and rebuilds on every change.
Iteras Trigger
Setting it up
Add Iteras Trigger to a workflow.
Pick what to listen for:
| Object | Event | Iteras event | Extra filter | | --- | --- | --- | --- | | Customer | Created |
customer:created| – | | Customer | Updated |customer:updated| – | | Subscription | Campaign Change Scheduled |subscription:registered-campaign-change| New Campaign | | Subscription | Campaign Changes |subscription:changed-campaign| New Campaign | | Subscription | Created |subscription:created| – | | Subscription | Period Changes |subscription:changed-period| – | | Subscription | Renewed |subscription:renewed| – | | Subscription | Status Changes |subscription:changed-status| New Status | | Subscription | Stop Cancelled |subscription:cancelled-stop| – | | Subscription | Stop Scheduled |subscription:registered-stop| – | | Subscription | Updated |subscription:updated| – |All nine subscription events Iteras documents are covered. Note the pair worth getting right for churn work: Stop Scheduled fires when a stop is registered and the subscription is still running until its end date, while Status Changes → Stopped fires when it actually stops. Stop Cancelled is the win-back — a registered stop was withdrawn.
Iteras also emits customer events beyond the two above (
customer:deleted,customer:password-reset-requested,customer:onetime-password-requested,customer:added-internal-note) and whole other objects (campaign:*,payment:*,customeroverride:*,customer-product-assignment:*,error:*). Adding any of them is one entry in the catalog.Copy the Production URL from the top of the node and paste it into the webhook settings in Iteras.
Activate the workflow. The production URL only accepts events while the workflow is active; the Test URL only works while you are pressing Listen for test event.
Iteras sends every event to that URL. The node answers all of them with
200 OK and only starts the workflow for events that match the configuration,
so Iteras never sees an error and never retries. The response body says what
happened, which is handy when checking a delivery in Iteras:
{ "received": 277, "matched": 119 }Filters
- New Status –
Anylets every status change through.Otherreveals a free text field for statuses that are not in the dropdown, so a new Iteras status works without a code change. - New Campaign – matches the campaign ID (
WEB_1M_ALL) or the campaign name (Alle titler – Digital (måned)). Comma separate several campaigns. Leave it empty to accept any campaign.
Both filters ignore casing and surrounding whitespace.
Output
One item per matching event, so a request carrying 277 events of which 119 match produces 119 items:
{
"event": {
"type": "subscription.statusChanged",
"sourceEvent": "subscription:changed-status",
"eventId": 92393807,
"timestamp": "2026-08-21T08:52:59"
},
"customer": { "id": 1001 },
"subscription": {
"id": 500001,
"status": "stopped",
"campaignId": "WEB_1M_ALL",
"campaignName": "All titles – Digital (month)",
"via": "administration",
"stopAt": "2026-08-21T08:52:59",
"stopPayment": "untilcurrentperiod",
"stopped": true,
"campaign": "3001",
"products": [{ "name": "WEB_DN — Website – Daily News", "external_id": "DN-E" }],
"data": { "websitearea": "dailynews" }
},
"raw": { "…": "the untouched Iteras event" }
}Following nodes can reference the fields directly:
{{ $json.event.type }}
{{ $json.customer.id }}
{{ $json.subscription.id }}
{{ $json.subscription.status }}
{{ $json.subscription.campaignId }}Normalization rules, so new Iteras fields keep working:
event,event_idandtimestampdescribe the event itself and becomeevent.sourceEvent,event.eventIdandevent.timestamp.event.typeis this package's own stable name for the event.- Fields prefixed with an object name go to that object:
customer_id→customer.id,subscription_id→subscription.id. - Every other top level field belongs to the object the event is about and is
only camelCased:
campaign_id→subscription.campaignId. - Nested values (
products,data,changes,ordering_form) are passed through exactly as Iteras sent them. subscription.campaignis Iteras' internal campaign reference ("3001"). The one you normally want issubscription.campaignId("WEB_1M_ALL").rawholds the original event. Turn it off under Options → Include Raw Event if the items should stay small.- If prefetching is enabled on the webhook in Iteras, the related objects it
attaches come through whole as
{{ $json.prefetch }}, untouched. That is the way to get customer details such as an email address without a separate API call.
Good to know
- Iteras posts a JSON array and batches events, so one request can carry hundreds of events across several event types.
- Each Iteras Trigger node has its own webhook URL. If Iteras only accepts one webhook URL, use one workflow with one trigger and branch with a Switch node instead of several trigger nodes.
- The node does not deduplicate. Iteras'
event_idis unique per event and is available as{{ $json.event.eventId }}if a workflow ever needs it. - There are no credentials yet. The node only receives webhooks, it does not call the Iteras API.
Iteras
Reads customer data from the Iteras API. Needs an Iteras API credential.
Credentials
In Iteras, create an API key under the API accesses section of your account settings, and give it access to the customer API. In n8n, add an Iteras API credential and paste the key in. Base URL only needs changing if Iteras has given you a different API address.
Press Test after saving. n8n calls Iteras' /access/ endpoint, which
returns the key's own configuration, so a wrong or unauthorized key fails
immediately rather than at the first real request.
The key is sent as the X-Iteras-Key header, which is what Iteras recommends —
the alternative is putting it in the URL, where it can leak into logs.
Operations
Customer → Get takes a customer ID and returns that customer. This is the
one to put straight after an Iteras Trigger: drag the customer ID from the
trigger, or use {{ $json.customer.id }}. Several IDs can be fetched at once by
separating them with commas.
Customer → Get Many returns many customers, with Return All or a Limit, and optional Filters:
| Filter | What it does | | --- | --- | | Email | Return the one customer with this email address | | Segment External ID | Return customers in an Iteras segment | | Subscription State | Return customers having a subscription that is awaiting, active, suspended or ended | | Custom Filter (JSON) | Any other Iteras filter condition, added on top of the rest |
Filters combine, so Email plus Subscription State means both must hold. Pagination
is handled for you — Iteras returns a next_url for large results and the node
follows it, stopping as soon as the limit is met.
Data to include, and Simplify
Data to Include maps to Iteras' fields parameter and decides how much comes
back: customer data, active subscriptions, full subscriptions, invoices,
payments, products, segments, balance, complaints, overrides, history. The
default is customer data plus active subscriptions. Asking for less keeps
responses small, which matters — Iteras allows about 5 requests per second.
Simplify is on by default and lifts the fields Iteras nests under data to
the top level, so an email is {{ $json.email }} rather than
{{ $json.data.email }}. The customer's id and the other sections are applied
last, so a field inside data can never shadow them. Turn Simplify off to get
Iteras' response exactly as sent.
Adding events and nodes
The event catalog in
nodes/Iteras/shared/events.ts drives the
dropdowns, the filtering and the output type. Adding an Iteras event is one
entry in that list — see docs/adding-events.md.
Layout:
nodes/
Iteras/ everything Iteras, so it can move to its own package later
iteras.svg shared by every Iteras node
IterasTrigger/ one folder per node
IterasTrigger.node.ts description + webhook handler
properties.ts the node UI
Iteras/
Iteras.node.ts the action node
properties.ts the node UI
shared/ reusable across every Iteras node
events.ts the event catalog
normalize.ts raw Iteras event -> item
payload.ts request body -> Iteras events
process.ts body + configuration -> items
filters.ts matching helpers
api.ts authenticated requests and next_url pagination
customers.ts filter building and simplifying
types.ts
credentials/
IterasApi.credentials.ts API key, auth header and the credential test
icons/ credential icons, referenced as file:../icons/...
test/ node:test suites, run against dist/Another Iteras node — an action node calling the Iteras API, say — gets its own
folder next to IterasTrigger/, reuses shared/, and is added to n8n.nodes
in package.json. A node for a different service is better off in its own
package, since this one is named after Iteras.
Development
npm run dev # n8n with this package linked, rebuilds on change
npm run build # compile to dist/ and copy icons
npm run lint # official n8n community node linter
npm run lint:fix
npm test # build, then run the test suites in test/test/fixtures/example-bulk.json is a batch of 277 Iteras events, taken from
real traffic and then anonymized: the IDs are remapped consistently and every
name belongs to a fictional publisher. The event mix, field shapes and edge
cases are untouched, which is the part worth testing against.
npm run dev keeps its own n8n in ~/.n8n-node-cli, separate from any n8n you
run yourself. Delete the folder to start over.
Author
Søren Pedersen — LinkedIn
Issues and pull requests are welcome at https://github.com/systemaddict/n8n-iteras.
Publishing and installing
n8n installs community nodes from npm by package name, so the package has to be published before a hosted instance can use it.
1. Point at the real repository
repository and homepage in package.json and the documentation URL in
nodes/Iteras/IterasTrigger/IterasTrigger.node.json are placeholders. Update
them to the real repository.
2. Publish to npm
npm login
npm publish --access publicprepublishOnly runs lint and build first, so a broken package cannot go out.
The tarball is dist/, README.md and LICENSE.md — around 12 kB, no source
and no secrets.
3. Install it on the n8n instance
In n8n: Settings → Community nodes → Install a community node, enter
n8n-nodes-iteras, accept the risk prompt.
Or over the public API:
curl -X POST "https://<your-n8n>/api/v1/community-packages" -H "X-N8N-API-KEY: $N8N_API_KEY" -H 'Content-Type: application/json' -d '{"name":"n8n-nodes-iteras"}'The node then shows up in the node panel as Iteras Trigger.
4. Surviving restarts on an ephemeral filesystem
Community packages are installed onto the container's disk. On hosts that do not persist it — Render, Fly, Heroku and most container platforms without a mounted volume — a restart or redeploy wipes them, and every node in your workflows breaks with "unknown node type". Set
N8N_REINSTALL_MISSING_PACKAGES=trueand n8n reinstalls its recorded packages at boot.
Releasing an update
npm version patch
npm publishThen Settings → Community nodes → Update in n8n, or
PATCH /api/v1/community-packages/n8n-nodes-iteras. Update
CHANGELOG.md with the version.
.github/workflows/publish.yml does the same from a git tag, with npm
provenance. Provenance is needed to apply for n8n's verified community node
list, not to install the package on your own instance —
N8N_UNVERIFIED_PACKAGES_ENABLED defaults to true.
Keeping it off the public registry
- Private npm package — publish under a scope and set
N8N_COMMUNITY_PACKAGES_REGISTRYandN8N_COMMUNITY_PACKAGES_AUTH_TOKENon the n8n instance. - Custom image — deploy Render from a Dockerfile based on
n8nio/n8nthat copiesdist/into/home/node/.n8n/custom/. No npm involved, but every change needs a redeploy.
