# Debugging database webhooks and pg_net

> Database webhooks or net.http_post calls that never reach your endpoint. How to read net._http_response, find timeouts and 401s, and test requests on SupaHost.

Source: https://supahost.app/kb/webhook-debugging · Updated 2026-11-11

## What you see

A database webhook or a `net.http_post` call in a trigger or cron job doesn't seem to do anything. Your endpoint logs show no request, or show an error, but the insert or the cron run that triggered it succeeded.

## Why it happens

pg_net is asynchronous. `net.http_post` puts the request in a queue and returns an ID straight away. A background worker sends it after the transaction commits and writes the result to `net._http_response`. So the SQL that fired the request can't see the outcome, and failures end up only in that table.

Common causes:

- **Timeout.** Database webhooks default to 1000 ms, and `net.http_post` defaults to a few seconds. A slow endpoint gets `timed_out = true` even though it did the work.
- **Missing or wrong auth header.** Your endpoint returns 401.
- **The transaction rolled back.** The request is only sent on commit.
- **Bad URL or DNS.** `error_msg` shows a resolution or connection error.
- **The trigger isn't attached** to the table or event you expected.

## How to fix it

1. Look at recent responses. Failures have a 4xx/5xx `status_code`, an `error_msg` or `timed_out`:

   ```sql
   select id, status_code, timed_out, error_msg, left(content, 200) as body, created
   from net._http_response
   where status_code >= 400 or error_msg is not null or timed_out
   order by created desc
   limit 20;
   ```

   Responses are only kept for a few hours, so check soon after the event.

2. Check for requests still waiting to be sent:

   ```sql
   select id, method, url, timeout_milliseconds
   from net.http_request_queue;
   ```

   This table holds headers too, including any keys you send. Any role that can read it can see them while a request waits.

   On SupaHost a committed request normally leaves this table within about a second, when it's handed to pg_net's worker. A row that stays here for more than a minute usually belongs to a transaction that hasn't committed yet (or a long-running one). If rows pile up anyway, email supahost@volods.com with the project name.

3. For database webhooks, match hook calls to responses:

   ```sql
   select h.hook_name, h.created_at, r.status_code, r.timed_out, r.error_msg
   from supabase_functions.hooks h
   left join net._http_response r on r.id = h.request_id
   order by h.created_at desc
   limit 20;
   ```

   No rows in `supabase_functions.hooks` means the trigger never fired. Check it exists:

   ```sql
   select tgname, tgenabled
   from pg_trigger
   where tgrelid = 'public.bookings'::regclass and not tgisinternal;
   ```

4. Raise the timeout when your endpoint is slow:

   ```sql
   select net.http_post(
     url := 'https://hooks.example.com/bookings',
     body := jsonb_build_object('booking_id', 42),
     timeout_milliseconds := 10000
   );
   ```

   Better still, have the endpoint reply right away and do the slow work afterwards.

5. Test with a request you can inspect. Send to an echo service or a request bin, then read the response `content` to see exactly what was sent.

## On SupaHost

- `pg_net` and the `supabase_functions` schema are installed in every project database, so webhooks work without setup.
- Calling your project's own APIs from the database uses the public URL, for example `https://app-one.acme.supahost.space/rest/v1/...`. Requests to `/rest/v1`, `/auth/v1` and `/storage/v1` need an `apikey` header, or they get 401 `No API key found in request`.
- `/functions/v1/*` doesn't need an `apikey`, but a function with **Require JWT** on needs `Authorization: Bearer <a project JWT>`. Otherwise it returns 401 `UNAUTHORIZED_NO_AUTH_HEADER`.
- Keep keys in [Vault](/docs/database/vault), not in trigger arguments or cron commands, which anyone with read access to `cron.job` or `pg_trigger` can see.
- When the request reaches your function, look in *Dashboard → your project → **Functions** tab → Logs* for the other half of the story.

## Related

- [Database webhooks and HTTP requests with pg_net](/docs/database/webhooks)
- [Edge Function returns 401](/kb/function-401)
- [Cron job not running](/kb/cron-job-not-running)
- [Logs and debugging](/docs/functions/logs)
