Integrate FastPix with Supabase
The @fastpix/supabase package provides a CLI that creates a fastpix schema in your database, deploys the edge functions that process webhooks, and keeps your data current automatically.
What you’ll get
After setup, your Supabase database has a fastpix schema that contains the following tables:
mediastores your on-demand video assets and their metadata.live_streamsstores live stream configurations, status, and secrets.uploadsstores direct-upload sessions.webhook_eventsstores the raw webhook event log for debugging and auditing.sync_statestores backfill and reconcile bookkeeping.
The CLI also creates four edge functions (fastpix-webhook, fastpix-worker, fastpix-reconcile, and fastpix-backfill), a pgmq job queue, and two Supabase Cron jobs, a queue drain and a nightly reconcile, that drive the sync.
Prerequisites
Before you begin, make sure you have the following:
- A FastPix account with an API token ID and token secret. To generate them, see Activate your account.
- A Supabase project with the Supabase CLI installed.
- Node.js version 20 or later.
- Docker, which local Supabase requires.
- Your Supabase service-role key. To find it, run
npx supabase status -o env. - Access to the FastPix dashboard, so that you can create a webhook and copy its signing secret.
Initialize the integration
Make sure Supabase is initialized in your project, and then initialize the FastPix integration:
The init command does the following:
- Creates the
fastpixschema and its tables. - Creates four functions in
supabase/functions:fastpix-webhook,fastpix-worker,fastpix-reconcile, andfastpix-backfill. These functions use the@fastpix/fp-sync-enginepackage to sync your data. - Sets up a pgmq job queue and two Supabase Cron jobs, a queue drain and a nightly reconcile, that drive the sync.
- Prompts you for
FASTPIX_TOKEN_ID,FASTPIX_TOKEN_SECRET, andFASTPIX_WEBHOOK_SECRET, and writes them tosupabase/functions/.env. - Sets
verify_jwtfor each function inconfig.toml. The webhook is set tofalse, because FastPix signs its requests instead of sending a Supabase JWT.
Everything init writes is copy-if-absent, so you can re-run the command safely without overwriting a file that you edited.
NOTE: If Supabase was already running when you ran
init, restart it withnpx supabase stopandnpx supabase startso that theconfig.tomlchanges take effect.
Configure environment variables
The init command prompts you for your credentials and writes them to supabase/functions/.env. If you skipped a value or need to change one, update the file directly:
Find your token ID and secret in the FastPix dashboard. You create the webhook secret in step 4, when you configure the webhook.
Create the Vault secrets
The two cron jobs call your edge functions over HTTP. They read the function URL and the service-role key from Supabase Vault, so that neither value is committed in a migration. Until these secrets exist, the queue fills but nothing drains, and no error is reported.
In the Supabase SQL Editor, run the following:
Locally, the URL must be reachable from inside the Postgres container, so use host.docker.internal rather than localhost. To find your service-role key, run npx supabase status -o env.
Run locally and configure the webhook
-
Serve the edge functions on port 54321:
-
Expose the functions to the internet with a tunneling tool such as ngrok. Your public webhook URL has a format like
https://d99d3b847eb8.ngrok-free.app/functions/v1/fastpix-webhook. -
In the FastPix dashboard, go to Org Settings > Webhooks > Create new webhook and enter that URL. For more information, see Set up webhooks.
-
Copy the signing secret from FastPix into
FASTPIX_WEBHOOK_SECRETinsupabase/functions/.env.
Verify that it works
-
In the FastPix dashboard, confirm that you’re in the correct environment, and then upload a media asset.
-
In your local Supabase dashboard, open the
mediatable in thefastpixschema. A row appears for the media, and itsmediaIdmatches the ID shown in the FastPix dashboard.
If the row doesn’t appear, query the event log to see where processing stopped:
For how to interpret the result, see Troubleshoot.
NOTE: Column names match the FastPix API, so they’re camelCase and require double quotes in SQL. Use
select "mediaId" from fastpix.media, notselect mediaId.
Backfill existing data
If your FastPix account already contains media or live streams, backfill them into your Supabase database:
The command prompts you for the database URL where it stores the data, and for your FastPix token ID and secret. To sync a single object type, pass it as an argument:
Backfill saves its place as it goes, so if it stops, you can run it again and it continues from where it left off.
To heal webhooks that you missed, reconcile resources that were active in the last few hours:
Backfill programmatically
You can also run the backfill from your own code with the sync engine:
Deploy to production
-
Link your project:
-
Run the migrations.
db pushapplies the queue and cron migrations, andmigratecreates thefastpixtables. Find your connection string in the dashboard under Connect. -
Add the Vault secrets that the cron jobs need. In the SQL Editor, run the following:
If a secret already exists, update it instead of creating it again:
-
Set the secrets for your edge functions from your
.envfile. Confirm thatsupabase/functions/.envholds the correct credentials first. -
Push the config. This step sends the
verify_jwtsettings. Without it, the webhook returns401. -
Deploy the functions:
-
Set up the production webhook. After you deploy
fastpix-webhook, its URL appears in the dashboard under Edge Functions. Create a webhook in FastPix with that URL, and then setFASTPIX_WEBHOOK_SECRETin the Supabase dashboard to the new signing secret.
After you deploy, secure the tables as described in the next section.
Secure the tables
WARNING: Until you complete this step, the
fastpixtables have no row-level security.live_streamsholdsstreamKeyandsrtSecret, which let anyone stream into your account, andwebhook_eventsstores raw payloads that can contain those same secrets. Never expose either table to your client.
In the SQL Editor, grant access to the service role and enable row-level security on every table:
Enabling row-level security with no policies denies everyone except the service role, which is the safe default. To show data in your app, create a view that exposes only the safe columns.
Query your data
The fastpix schema is written by the service role and isn’t exposed to your client until you add a safe view. For server-side queries, use the service-role key, which bypasses row-level security:
WARNING: The service-role key bypasses row-level security and belongs only in server-side code. Never expose it in a client application. To read FastPix data from the client, add your own row-level security policies or expose a view with only the safe columns.
Column names match the FastPix API, so they’re camelCase and require double quotes in SQL. Use select "mediaId" from fastpix.media, not select mediaId.
Use the sync engine with any Postgres
If you don’t use Supabase, use the @fastpix/fp-sync-engine package directly. It’s a framework-free TypeScript library that works with any Postgres database and runs on both Node.js and Deno.
Install the package:
Create the schema once, initialize the engine, and process webhooks in your own server. The following example uses Express:
The engine provides the same backfill and reconcile capabilities as the CLI. For the full configuration and API reference, see the @fastpix/fp-sync-engine README.
Troubleshoot
No rows in fastpix.webhook_events.
FastPix isn’t reaching your webhook. Check that your tunnel URL is current and that the webhook secret in FastPix matches FASTPIX_WEBHOOK_SECRET.
Rows stuck at received.
Nothing is draining the queue. Confirm that both Vault secrets exist and hold the correct values. See Create the Vault secrets.
The webhook returns 401 in production.
You didn’t push the config, so verify_jwt is still true for fastpix-webhook. Run npx supabase config push.
A SQL query returns a column-not-found error.
Column names are camelCase and need double quotes: select "mediaId" from fastpix.media.