curl / plain scripts
It's a REST API underneath everything else — no SDK required. This walkthrough matches the REST reference exactly.
BASE=https://api.pendnt.dev
KEY="$PENDNT_API_KEY" # from https://api.pendnt.dev/signup
# 1. Create an inbound endpoint and send it a webhook
EP=$(curl -s -X POST "$BASE/v1/endpoints" \
-H "authorization: Bearer $KEY" -d '{"name":"gh"}')
SLUG=$(echo "$EP" | jq -r .slug)
curl -s -X POST "$BASE/in/$SLUG" \
-H 'content-type: application/json' -d '{"hello":"world"}'
curl -s "$BASE/v1/events" -H "authorization: Bearer $KEY" | jq
# 2. Ask for an approval and long-poll for the answer
curl -s -X POST "$BASE/v1/requests" -H "authorization: Bearer $KEY" \
-d '{"kind":"approval","title":"Deploy to prod?","wait_s":25}'
# 3. Fire-and-forget notification
curl -s -X POST "$BASE/v1/notify" -H "authorization: Bearer $KEY" \
-d '{"message":"build finished"}'
# 4. KV scratchpad
curl -s -X PUT "$BASE/v1/kv/last_run" -H "authorization: Bearer $KEY" \
-d '{"value":"2026-08-29T00:00:00Z"}'
curl -s "$BASE/v1/kv/last_run" -H "authorization: Bearer $KEY"
# 5. Schedule a wakeup 60s out
curl -s -X POST "$BASE/v1/wakeups" -H "authorization: Bearer $KEY" \
-d '{"in_s":60,"payload":{"check":"status"}}'
Blocking vs. resumable
Step 2 above passes wait_s: 25, so the call blocks for up to 25 seconds waiting
for an operator to answer (from the web inbox, email, or any connected channel). If it's still
pending after that, re-poll the same request instead of creating a new one:
RID="req_..." # the "id" from the create-request response
curl -s "$BASE/v1/requests/$RID?wait_s=25" -H "authorization: Bearer $KEY"
The request stays open (durable) for timeout_s seconds regardless — default
86400 (24h) — so a script can poll again minutes or hours later with the same id and still get an
answer.
Answering from a script (testing)
In production, the link an operator taps comes from a delivery channel (email, Telegram, etc.)
— see Channels. For local testing or scripted answers, the
answer endpoint just needs a valid request_id + signature pair:
curl -X POST "$BASE/a/$RID/$SIG" \
-H 'content-type: application/json' \
-d '{"action":"approve"}'
action is approve, deny, or answer (with
an optional text field) — see the operator answer
page reference. The signature is workspace-specific and not something you compute
client-side in production; it's handed to you pre-signed inside each delivered link.
Cancel a pending request
curl -s -X POST "$BASE/v1/requests/$RID/cancel" -H "authorization: Bearer $KEY"
List and cancel a wakeup
curl -s "$BASE/v1/wakeups" -H "authorization: Bearer $KEY" | jq
WID="wkp_..."
curl -s -X DELETE "$BASE/v1/wakeups/$WID" -H "authorization: Bearer $KEY"
Every route used above, plus errors and rate limits, is documented in full in the REST reference.