Choose an approach
What you need
- A service token, saved as a secret in your CI system, for example
SUPRSEND_SERVICE_TOKENin 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/).
Keep your assets in Git
Pull the current live state from your staging workspace into the repo, then commit it:./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
--commitmakes 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, soevent pushdoesn’t take--commit.category pushsends preference-category translations live either way. If you leave--commitoff,event pushfails for events linked to schemas that aren’t live yet. - Template variants commit together.
template push --commitcommits 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-Foff 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
runscripts withbash -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
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 withsuprsend sync. Run it from a manual job so a person decides when to release:
.github/workflows/suprsend-promote.yml
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.
--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,syncandworkflow disablerun straight away, so check-w(--toforsync) before you run them. - Logs are hidden. When
stderrisn’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_URLandSUPRSEND_MGMNT_URLenvironment 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 thesuprsend-cli skill so it uses the right commands and flags when it writes or changes these workflows.