Every backup product publishes a list of supported sources, and every list is missing something you run. An in-house service with a bespoke export. A SaaS with an API and no integration. A queue, a search index, a licence server, a thing somebody wrote in 2019 that nobody wants to touch.
The usual answer is "it is on the roadmap". The better answer is an escape hatch.
The contract
If you can write a script that produces a file, you have a backup source. The whole interface is one environment variable:
#!/usr/bin/env bash
set -euo pipefail
# SAVED_OUTPUT is a path. Write your backup there and exit zero.
curl --fail --silent --show-error \
-H "Authorization: Bearer $VENDOR_TOKEN" \
https://api.vendor.example/v1/export \
> "$SAVED_OUTPUT"That is the entire integration. Point a backup at that script, give it a schedule, and it now has the same retention, the same encryption, the same delivery to your own bucket and the same run history as a Postgres source.
Three rules the contract enforces
Write to $SAVED_OUTPUT, not stdout. Anything on stdout is treated as a log,
which means it shows up in the run record where it is useful for debugging and
does not end up inside your backup. A script that prints its data instead of
writing it produces a zero-byte artifact.
An empty file is a failure, not a success. If the script exits zero and
$SAVED_OUTPUT is empty, the run fails and tells you so, rather than archiving
nothing and going green. This is the single most valuable line in the whole
feature, because "exited zero, produced nothing" is the most common way a
homemade backup lies to you.
Exit non-zero to fail the run. Use set -euo pipefail and let the shell do
it. A curl that 404s inside a pipe will not fail the script without it, which is
how people end up archiving an HTML error page.
What it is good for
The pattern is worth reaching for in more cases than people expect:
| Situation | The script |
|---|---|
| SaaS with an export API and no integration | curl the export endpoint |
| A database we do not support | Its own dump tool, redirected to $SAVED_OUTPUT |
| Several things that belong together | tar them into one artifact |
| A dump that needs pre-processing | Dump, filter out the two tables you cannot store, then write |
| Compliance evidence | Run the report, save the output, keep it under a retention lock |
The fourth row is the interesting one. Because you control the script, you can strip what must not be stored before it is ever archived, which is much easier than deleting it from artifacts afterwards.
1env var
The entire interface
0
Integrations you have to wait for
0bytes
What silently passes as success
Where it runs, and why that matters
Script sources run on a worker on your own machine, not on ours. That is a deliberate constraint rather than a limitation we have not got to yet.
A script is arbitrary code with access to whatever credentials it needs. Running that on our infrastructure would mean you hand us the credentials and trust us to execute your code, which is a much larger ask than "back up this database". So the script runs where you already have the access, and we never see the token, the code, or the bytes.
The honest caveat
An escape hatch is not the same as an integration. You own the script: when the vendor changes their export endpoint, your backup breaks and you fix it.
What you get in exchange is that you are never blocked. Everything around the script, the scheduling, retries, retention, encryption, delivery to your own bucket and a record of what each run produced, is the same machinery the built-in sources use. Only the fifteen lines that produce the file are yours.