Skip to main content
Use the SuprSend CLI in a pipeline to release notification changes the way you release code: keep workflows, templates and the rest as files in Git, review them in pull requests, and push them to production when you merge. The CLI authenticates with a service token, so no one has to sign in.

Choose an approach

What you need

  • A service token, saved as a secret in your CI system, for example SUPRSEND_SERVICE_TOKEN in GitHub Actions.
  • Node.js 18 or later on the runner, to run the CLI with npx. You can also install the CLI another way.
  • Your notification assets in the repo, in the folder layout the CLI uses (default ./suprsend/).
Service tokens are account-wide: a token can act on every workspace in your account. Keep it in your CI system’s secret store, and limit who can run jobs that use it, for example with GitHub environment protection rules.

Keep your assets in Git

Pull the current live state from your staging workspace into the repo, then commit it:
Each command writes to its own folder under ./suprsend/, for example ./suprsend/workflows/<slug>/workflow.json, and overwrites the files it pulls. -F uses the default folder without asking. Without it, a pull whose folder doesn’t exist yet asks for one in a terminal, and fails with exit code 64 in a non-interactive shell. From then on, change the files in pull requests, or pull again after building in the dashboard.

Release to production on merge

This GitHub Actions workflow pushes the assets in ./suprsend/ to production and commits them when changes reach main. It pushes them in the same order suprsend sync uses, so categories and schemas exist before the templates and workflows that use them.
.github/workflows/suprsend-release.yml

How a release behaves

  • --commit makes changes live. With --commit, workflows, templates, schemas, categories and translations go live. Without it, they’re saved as drafts, so someone can review and commit them in the dashboard.
  • Events and category translations go live without --commit. Events have no draft state, so event push doesn’t take --commit. category push sends preference-category translations live either way. If you leave --commit off, event push fails for events linked to schemas that aren’t live yet.
  • Template variants commit together. template push --commit commits all of a template’s variants together, so one invalid variant fails the whole template with exit code 1. With -F, it commits only the variants that pass validation and skips the rest with a warning. Leave -F off in CI, as above, so a bad variant fails the job instead of being skipped.
  • A failed step stops the release, but isn’t rolled back. The step stops at the first command that fails, because GitHub Actions runs run scripts with bash -e. The asset types pushed before the failure, and the items that succeeded in the failing command, are already live. Fix the cause and re-run the job.
  • Roll back with Git. To roll back a release, revert the commit on main. The release job then pushes and commits the previous files.
  • Keep only the asset types you use. Remove the commands for asset types you don’t store in the repo. A push fails with exit code 2 when its folder, for example ./suprsend/templates, doesn’t exist.
Pushes and pulls never delete anything:
  • Deleted in the repo: the asset stays in the workspace. Delete it in the dashboard too.
  • Deleted in the workspace: its folder stays in the repo after a pull. Delete the folder yourself.
  • Renamed slug: counts as a new asset. The old one stays until you delete it.

Check files in pull requests

--dry-run reads and parses the local files without calling SuprSend, so it catches broken JSON before merge. A file that doesn’t parse fails the check with exit code 2. The CLI still needs a token value to start, but a dry run never uses it, so a placeholder works and keeps your real token out of pull-request jobs.
.github/workflows/suprsend-check.yml
As in the release job, keep only the commands for asset types you store in the repo. A dry run checks only local files: that they parse, and for schemas that payload_schema.json compiles as a JSON Schema. SuprSend validates the content itself when you push. category push --dry-run checks categories.json but doesn’t read the category translation files, so a broken translation file is only caught by a real push.

Promote staging to production with sync

If you build in the staging workspace instead of in files, promote everything at once with suprsend sync. Run it from a manual job so a person decides when to release:
.github/workflows/suprsend-promote.yml
sync pushes and commits every synced asset, so the changes go live in production immediately.
  • Local files are pushed too. It also pushes workflows, schemas, events, templates and translations already in its local directory, not only what it pulled from staging. Use a fresh --dir, as above, so only assets from staging are pushed.
  • Invalid template variants are skipped. Unlike template push --commit, sync commits the valid variants and skips invalid ones with a warning, which CI logs hide. It still exits with 0 unless every changed variant of a template fails, so check the destination after a sync.

Keep generated types in step

If your code uses types generated from your payload schemas, regenerate them in CI and fail the build when they’re out of date:
generate-types reads the live schemas in the workspace, not the payload_schema.json files in your repo. So run this check after the release job on main, or on a schedule, not on pull requests:
  • On a pull request, a schema change in the repo isn’t live yet, so the check can’t see it.
  • A schema committed in the workspace by someone else would fail the check on unrelated pull requests.
  • The check needs your real service token, which you keep out of pull-request jobs.
Point --workspace at the workspace your repo releases to, as above. Deleting the file first matters: if generation fails, for example on an expired token, the command still exits with 0, and the missing file then shows up in git diff.

How the CLI behaves in CI

  • No prompts. Confirmation prompts appear only in an interactive terminal. In CI, --commit, sync and workflow disable run straight away, so check -w (--to for sync) before you run them.
  • Logs are hidden. When stderr isn’t a terminal, as in CI runners, the CLI hides its log lines and prints only command output and a JSON error. Rely on the exit code.
  • Re-runs are safe. When there’s nothing new to commit, the command exits with 0. In a terminal, it also logs “no changes to commit”.
  • Self-hosted or BYOC. Point the CLI at your deployment with the SUPRSEND_BASE_URL and SUPRSEND_MGMNT_URL environment variables, or use a CLI profile.

Let a coding agent write the pipeline

If you use a coding agent such as Claude Code or Cursor, add the suprsend-cli skill so it uses the right commands and flags when it writes or changes these workflows.