env | grep -i supabase | sed -E 's/(KEY|PASSWORD)=.*/\1=***REDACTED***/'
SUPABASE_DB_PASSWORD=***REDACTED*** SUPABASE_DB_URL=<redacted:SUPABASE_DB_URL> SUPABASE_URL=https://<ref>.supabase.co SUPABASE_SERVICE_ROLE_KEY=***REDACTED*** SUPABASE_PROJECT_REF=<ref> SUPABASE_ANON_KEY=***REDACTED***
which psql curl jq node 2>&1; echo "---"; psql --version 2>&1
/usr/bin/psql /usr/bin/curl /usr/bin/jq /usr/bin/node --- psql (PostgreSQL) 18.4 (Debian 18.4-1.pgdg12+1)
export PGPASSWORD=$SUPABASE_DB_PASSWORD
psql "$SUPABASE_DB_URL" -c "\d public.signups"
echo "---extensions---"
psql "$SUPABASE_DB_URL" -c "select extname, extversion from pg_extension order by extname;"
echo "---receiver test---"
curl -s -o /dev/null -w "%{http_code}\n" -X POST "$SUPABASE_URL/functions/v1/hook-recorder" -H "Content-Type: application/json" -d '{}'
Table "public.signups"
Column | Type | Collation | Nullable | Default
------------+--------------------------+-----------+----------+----------------------------------
id | bigint | | not null | generated by default as identity
email | text | | not null |
plan | text | | not null | 'free'::text
created_at | timestamp with time zone | | not null | now()
Indexes:
"signups_pkey" PRIMARY KEY, btree (id)
---extensions---
extname | extversion
--------------------+------------
pg_stat_statements | 1.11
pgcrypto | 1.3
plpgsql | 1.0
supabase_vault | 0.3.1
uuid-ossp | 1.1
(5 rows)
---receiver test---
401
export PGPASSWORD=$SUPABASE_DB_PASSWORD echo "--- available extensions matching net ---" psql "$SUPABASE_DB_URL" -c "select name, default_version, installed_version from pg_available_extensions where name ilike '%net%' or name ilike '%http%';" echo "--- schemas ---" psql "$SUPABASE_DB_URL" -c "\dn"
--- available extensions matching net ---
name | default_version | installed_version
--------+-----------------+-------------------
http | 1.6 |
pg_net | 0.20.4 |
(2 rows)
--- schemas ---
List of schemas
Name | Owner
----------------+-------------------
app_private | postgres
auth | supabase_admin
extensions | postgres
graphql | supabase_admin
graphql_public | supabase_admin
pgbouncer | pgbouncer
public | pg_database_owner
realtime | supabase_admin
storage | supabase_admin
vault | supabase_admin
(10 rows)
export PGPASSWORD=$SUPABASE_DB_PASSWORD psql "$SUPABASE_DB_URL" -c "create extension if not exists pg_net schema extensions;" psql "$SUPABASE_DB_URL" -c "select extname, extnamespace::regnamespace from pg_extension where extname='pg_net';"
CREATE EXTENSION extname | extnamespace ---------+-------------- pg_net | extensions (1 row)
# Test the receiver with anon key and service role key to see which is accepted
curl -s -o /tmp/resp1.txt -w "ANON: %{http_code}\n" -X POST "$SUPABASE_URL/functions/v1/hook-recorder" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SUPABASE_ANON_KEY" \
-d '{"email":"probe@example.com","plan":"free"}'
cat /tmp/resp1.txt; echo
curl -s -o /tmp/resp2.txt -w "SERVICE: %{http_code}\n" -X POST "$SUPABASE_URL/functions/v1/hook-recorder" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SUPABASE_SERVICE_ROLE_KEY" \
-d '{"email":"probe2@example.com","plan":"free"}'
cat /tmp/resp2.txt; echo
ANON: 200
{"ok":true}
SERVICE: 200
{"ok":true}
export PGPASSWORD=$SUPABASE_DB_PASSWORD psql "$SUPABASE_DB_URL" -c "\d public.webhook_receipts" psql "$SUPABASE_DB_URL" -c "select * from public.webhook_receipts order by id desc limit 5;"
Table "public.webhook_receipts"
Column | Type | Collation | Nullable | Default
-------------+--------------------------+-----------+----------+----------------------------------
id | bigint | | not null | generated by default as identity
received_at | timestamp with time zone | | not null | now()
payload | jsonb | | not null |
Indexes:
"webhook_receipts_pkey" PRIMARY KEY, btree (id)
id | received_at | payload
----+-------------------------------+-------------------------------------------------
3 | 2026-07-24 05:06:51.508947+00 | {"plan": "free", "email": "probe2@example.com"}
2 | 2026-07-24 05:06:51.196946+00 | {"plan": "free", "email": "probe@example.com"}
(2 rows)
export PGPASSWORD=$SUPABASE_DB_PASSWORD psql "$SUPABASE_DB_URL" -c "\d vault.secrets" 2>&1 | head -30 echo "---" psql "$SUPABASE_DB_URL" -c "select proname, pronamespace::regnamespace from pg_proc where proname ilike '%create_secret%' or proname ilike '%decrypted_secret%';" 2>&1
Table "vault.secrets"
Column | Type | Collation | Nullable | Default
-------------+--------------------------+-----------+----------+-----------------------------------
id | uuid | | not null | gen_random_uuid()
name | text | | |
description | text | | not null | ''::text
secret | text | | not null |
key_id | uuid | | |
nonce | bytea | | | vault._crypto_aead_det_noncegen()
created_at | timestamp with time zone | | not null | CURRENT_TIMESTAMP
updated_at | timestamp with time zone | | not null | CURRENT_TIMESTAMP
Indexes:
"secrets_pkey" PRIMARY KEY, btree (id)
"secrets_name_idx" UNIQUE, btree (name) WHERE name IS NOT NULL
---
proname | pronamespace
---------------+--------------
create_secret | vault
(1 row)
export PGPASSWORD=$SUPABASE_DB_PASSWORD
# Store secrets in vault (idempotent-ish: delete existing with same name first)
psql "$SUPABASE_DB_URL" <<SQL
do \$\$
begin
delete from vault.secrets where name = 'project_url';
delete from vault.secrets where name = 'service_role_key';
end \$\$;
select vault.create_secret('$SUPABASE_URL', 'project_url', 'Base URL of this Supabase project');
select vault.create_secret('$SUPABASE_SERVICE_ROLE_KEY', 'service_role_key', 'Service role JWT used for internal webhook calls');
SQL
DO
create_secret
--------------------------------------
603fc4db-6e11-4f7a-989e-e5259b6b67b9
(1 row)
create_secret
--------------------------------------
e5a09663-2d57-4cd1-8886-def1a3074bfd
(1 row)
export PGPASSWORD=$SUPABASE_DB_PASSWORD
psql "$SUPABASE_DB_URL" -c "select name, decrypted_secret from vault.decrypted_secrets where name in ('project_url','service_role_key');"
name | decrypted_secret ------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- project_url | https://<ref>.supabase.co service_role_key | <redacted:SUPABASE_SERVICE_ROLE_KEY> (2 rows)
export PGPASSWORD=$SUPABASE_DB_PASSWORD
psql "$SUPABASE_DB_URL" <<'SQL'
create or replace function public.signups_webhook_trigger()
returns trigger
language plpgsql
security definer
set search_path = public, extensions, vault
as $$
declare
v_url text;
v_key text;
v_payload jsonb;
v_request_id bigint;
begin
select decrypted_secret into v_url
from vault.decrypted_secrets where name = 'project_url';
select decrypted_secret into v_key
from vault.decrypted_secrets where name = 'service_role_key';
v_payload := jsonb_build_object(
'email', NEW.email,
'plan', NEW.plan,
'id', NEW.id,
'created_at', NEW.created_at
);
select net.http_post(
url := v_url || '/functions/v1/hook-recorder',
headers := jsonb_build_object(
'Content-Type', 'application/json',
'Authorization', 'Bearer ' || v_key
),
body := v_payload
) into v_request_id;
return NEW;
end;
$$;
drop trigger if exists signups_webhook_trigger on public.signups;
create trigger signups_webhook_trigger
after insert on public.signups
for each row
execute function public.signups_webhook_trigger();
SQL
CREATE FUNCTION DROP TRIGGER CREATE TRIGGER
NOTICE: trigger "signups_webhook_trigger" for relation "public.signups" does not exist, skipping
export PGPASSWORD=$SUPABASE_DB_PASSWORD psql "$SUPABASE_DB_URL" -c "select n.nspname, p.proname from pg_proc p join pg_namespace n on n.oid=p.pronamespace where p.proname='http_post';"
nspname | proname ---------+----------- net | http_post (1 row)
export PGPASSWORD=$SUPABASE_DB_PASSWORD
psql "$SUPABASE_DB_URL" -c "\dn net"
psql "$SUPABASE_DB_URL" -c "select current_setting('search_path');"
List of schemas
Name | Owner
------+----------------
net | supabase_admin
(1 row)
current_setting
------------------------------
"\$user", public, extensions
(1 row)
export PGPASSWORD=$SUPABASE_DB_PASSWORD
psql "$SUPABASE_DB_URL" <<'SQL'
create or replace function public.signups_webhook_trigger()
returns trigger
language plpgsql
security definer
set search_path = public, extensions, vault, net
as $$
declare
v_url text;
v_key text;
v_payload jsonb;
v_request_id bigint;
begin
select decrypted_secret into v_url
from vault.decrypted_secrets where name = 'project_url';
select decrypted_secret into v_key
from vault.decrypted_secrets where name = 'service_role_key';
v_payload := jsonb_build_object(
'email', NEW.email,
'plan', NEW.plan,
'id', NEW.id,
'created_at', NEW.created_at
);
select net.http_post(
url := v_url || '/functions/v1/hook-recorder',
headers := jsonb_build_object(
'Content-Type', 'application/json',
'Authorization', 'Bearer ' || v_key
),
body := v_payload
) into v_request_id;
raise log 'signups_webhook_trigger: dispatched request_id=%', v_request_id;
return NEW;
end;
$$;
SQL
CREATE FUNCTION
export PGPASSWORD=$SUPABASE_DB_PASSWORD
psql "$SUPABASE_DB_URL" -c "select rolname from pg_roles where rolname in ('postgres','authenticator','anon','authenticated','service_role');"
psql "$SUPABASE_DB_URL" -c "\dp net.*" 2>&1 | head -20
psql "$SUPABASE_DB_URL" -c "select proowner::regrole from pg_proc where proname='signups_webhook_trigger';"
rolname
---------------
authenticated
anon
service_role
postgres
authenticator
(5 rows)
Access privileges
Schema | Name | Type | Access privileges | Column privileges | Policies
--------+---------------------------+----------+----------------------------------------+-------------------+----------
net | _http_response | table | supabase_admin=arwdDxtm/supabase_admin+| |
| | | =arwdDxtm/supabase_admin | |
net | http_request_queue | table | supabase_admin=arwdDxtm/supabase_admin+| |
| | | =arwdDxtm/supabase_admin | |
net | http_request_queue_id_seq | sequence | supabase_admin=rwU/supabase_admin +| |
| | | =rwU/supabase_admin | |
(3 rows)
proowner
----------
postgres
(1 row)
export PGPASSWORD=$SUPABASE_DB_PASSWORD
psql "$SUPABASE_DB_URL" -c "select net.http_post(url := '$SUPABASE_URL/functions/v1/hook-recorder', headers := jsonb_build_object('Content-Type','application/json','Authorization','Bearer $SUPABASE_ANON_KEY'), body := jsonb_build_object('email','direct_net_test@example.com','plan','free')) as request_id;"
sleep 3
psql "$SUPABASE_DB_URL" -c "select * from public.webhook_receipts order by id desc limit 3;"
request_id
------------
1
(1 row)
id | received_at | payload
----+-------------------------------+----------------------------------------------------------
4 | 2026-07-24 05:07:53.483842+00 | {"plan": "free", "email": "direct_net_test@example.com"}
3 | 2026-07-24 05:06:51.508947+00 | {"plan": "free", "email": "probe2@example.com"}
2 | 2026-07-24 05:06:51.196946+00 | {"plan": "free", "email": "probe@example.com"}
(3 rows)
export PGPASSWORD=$SUPABASE_DB_PASSWORD
TEST_EMAIL="trigger_test_$(date +%s)@example.com"
echo "Inserting with email=$TEST_EMAIL"
psql "$SUPABASE_DB_URL" -c "insert into public.signups (email, plan) values ('$TEST_EMAIL', 'pro') returning *;"
echo "Waiting for async webhook delivery..."
sleep 4
psql "$SUPABASE_DB_URL" -c "select id, received_at, payload from public.webhook_receipts where payload->>'email' = '$TEST_EMAIL';"
Inserting with email=trigger_test_1784869682@example.com
id | email | plan | created_at
----+-------------------------------------+------+-------------------------------
1 | trigger_test_1784869682@example.com | pro | 2026-07-24 05:08:03.147095+00
(1 row)
INSERT 0 1
Waiting for async webhook delivery...
id | received_at | payload
----+------------------------------+----------------------------------------------------------------------------------------------------------------------------
5 | 2026-07-24 05:08:03.31952+00 | {"id": 1, "plan": "pro", "email": "trigger_test_1784869682@example.com", "created_at": "2026-07-24T05:08:03.147095+00:00"}
(1 row)
TEST_EMAIL2="rest_client_test_$(date +%s)@example.com"
echo "Inserting via PostgREST (anon key) with email=$TEST_EMAIL2"
curl -s -X POST "$SUPABASE_URL/rest/v1/signups" \
-H "apikey: $SUPABASE_ANON_KEY" \
-H "Authorization: Bearer $SUPABASE_ANON_KEY" \
-H "Content-Type: application/json" \
-H "Prefer: return=representation" \
-d "{\"email\":\"$TEST_EMAIL2\",\"plan\":\"enterprise\"}"
echo
echo "Waiting..."
sleep 4
export PGPASSWORD=$SUPABASE_DB_PASSWORD
psql "$SUPABASE_DB_URL" -c "select id, received_at, payload from public.webhook_receipts where payload->>'email' = '$TEST_EMAIL2';"
Inserting via PostgREST (anon key) with email=rest_client_test_1784869694@example.com
[{"id":2,"email":"rest_client_test_1784869694@example.com","plan":"enterprise","created_at":"2026-07-24T05:08:14.838134+00:00"}]
Waiting...
id | received_at | payload
----+------------------------------+---------------------------------------------------------------------------------------------------------------------------------------
6 | 2026-07-24 05:08:14.99918+00 | {"id": 2, "plan": "enterprise", "email": "rest_client_test_1784869694@example.com", "created_at": "2026-07-24T05:08:14.838134+00:00"}
(1 row)
15 earlier narration turn(s) are in the raw transcript.
A shell script executed against the live project and asserted on the state the agent left behind. No model judged another model.
Raw transcript · Task definition and verifier · Every attempt