curl --request POST \
--url https://app.ohmyho.st/v1/projects/{project_id}/database/watches \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"environment": "dev",
"table": "orders",
"columns": [
"id",
"total"
]
}
'import requests
url = "https://app.ohmyho.st/v1/projects/{project_id}/database/watches"
payload = {
"environment": "dev",
"table": "orders",
"columns": ["id", "total"]
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({environment: 'dev', table: 'orders', columns: ['id', 'total']})
};
fetch('https://app.ohmyho.st/v1/projects/{project_id}/database/watches', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.ohmyho.st/v1/projects/{project_id}/database/watches",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'environment' => 'dev',
'table' => 'orders',
'columns' => [
'id',
'total'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.ohmyho.st/v1/projects/{project_id}/database/watches"
payload := strings.NewReader("{\n \"environment\": \"dev\",\n \"table\": \"orders\",\n \"columns\": [\n \"id\",\n \"total\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.ohmyho.st/v1/projects/{project_id}/database/watches")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"environment\": \"dev\",\n \"table\": \"orders\",\n \"columns\": [\n \"id\",\n \"total\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.ohmyho.st/v1/projects/{project_id}/database/watches")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"environment\": \"dev\",\n \"table\": \"orders\",\n \"columns\": [\n \"id\",\n \"total\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "pgcf_watch_0a1b2c3d",
"environment": "dev",
"schema": "public",
"table": "orders",
"columns": [
"id",
"total"
],
"operations": [
"insert",
"update",
"delete"
],
"topic": "orders",
"event_type": "data.orders"
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}{
"type": "https://docs.ohmyho.st/errors/resource-not-found",
"title": "Resource not found",
"status": 404,
"code": "resource_not_found",
"request_id": "req_01J00000000000000000000000",
"retryable": false,
"suggested_action": "Check the resource identifier and your access scope."
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}Watch the columns of one table for data events
Attaches the pgcf.capture trigger that publishes only the listed columns of the table as data events of one environment. Subscribe to the returned event_type with a database webhook. The request wakes a sleeping database. Repeating an identical request leaves the watch unchanged; repeating it with other columns or operations replaces the trigger. A reached Stop budget refuses with project_budget_exceeded (402). At most 100 watches exist per database.
curl --request POST \
--url https://app.ohmyho.st/v1/projects/{project_id}/database/watches \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"environment": "dev",
"table": "orders",
"columns": [
"id",
"total"
]
}
'import requests
url = "https://app.ohmyho.st/v1/projects/{project_id}/database/watches"
payload = {
"environment": "dev",
"table": "orders",
"columns": ["id", "total"]
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({environment: 'dev', table: 'orders', columns: ['id', 'total']})
};
fetch('https://app.ohmyho.st/v1/projects/{project_id}/database/watches', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.ohmyho.st/v1/projects/{project_id}/database/watches",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'environment' => 'dev',
'table' => 'orders',
'columns' => [
'id',
'total'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.ohmyho.st/v1/projects/{project_id}/database/watches"
payload := strings.NewReader("{\n \"environment\": \"dev\",\n \"table\": \"orders\",\n \"columns\": [\n \"id\",\n \"total\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.ohmyho.st/v1/projects/{project_id}/database/watches")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"environment\": \"dev\",\n \"table\": \"orders\",\n \"columns\": [\n \"id\",\n \"total\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.ohmyho.st/v1/projects/{project_id}/database/watches")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"environment\": \"dev\",\n \"table\": \"orders\",\n \"columns\": [\n \"id\",\n \"total\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "pgcf_watch_0a1b2c3d",
"environment": "dev",
"schema": "public",
"table": "orders",
"columns": [
"id",
"total"
],
"operations": [
"insert",
"update",
"delete"
],
"topic": "orders",
"event_type": "data.orders"
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}{
"type": "https://docs.ohmyho.st/errors/resource-not-found",
"title": "Resource not found",
"status": 404,
"code": "resource_not_found",
"request_id": "req_01J00000000000000000000000",
"retryable": false,
"suggested_action": "Check the resource identifier and your access scope."
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}{
"type": "<string>",
"title": "<string>",
"status": 499,
"code": "invalid_request",
"request_id": "<string>",
"retryable": true,
"suggested_action": "<string>",
"detail": "<string>",
"instance": "<string>",
"retry_after_seconds": 43200
}Authorizations
WorkOS access JWT or a user-owned WorkOS API key. User keys are bound to one organization and restricted to their enabled product permissions. Session-only onboarding and session revocation require an interactive access JWT. No cookie session is assumed.
Headers
Optional caller-provided correlation identifier.
1 - 128Identifies one mutation and its canonical request payload.
1 - 128Path Parameters
Project identifier.
^[0-9A-HJKMNP-TV-Z]{26}$Body
dev, prod Ordinary table owned by the application, created by a deployed migration.
^[A-Za-z_][A-Za-z0-9_]{0,62}$Columns published with every event, exactly as written; names are case-sensitive.
1 - 32 elements^[A-Za-z_][A-Za-z0-9_]{0,62}$Schema of the table, public when omitted. The schemas pgcf, ohmyhost, information_schema and pg_* cannot be watched.
^[A-Za-z_][A-Za-z0-9_]{0,62}$Row changes that publish an event; all three when omitted.
1 - 3 elementsinsert, update, delete Response
The watch with the event type its deliveries carry.
^pgcf_watch_[0-9a-f]{8}$dev, prod ^[A-Za-z_][A-Za-z0-9_]{0,62}$^[A-Za-z_][A-Za-z0-9_]{0,62}$1 - 32 elements^[A-Za-z_][A-Za-z0-9_]{0,62}$1 - 3 elementsinsert, update, delete Topic of the watched table, derived by the platform from its name.
^[a-z][a-z0-9_]{0,47}$Event type of the rows of the table; pass it to a database webhook.
^data\.[a-z][a-z0-9_]{0,47}$