How does an agent get an answer?
POST /escalations returns poll_url and poll_interval_seconds. GET that URL until status is resolved, expired, or cancelled, or supply a callback URL for an HMAC-signed webhook.
POST an escalation, notify Slack or email with a single-use reply link, then poll or receive a signed callback. Context stays on the reply page. It is never in the notification.
PingHuman creates real human review escalations. This playground is a static sample of POST /escalations so the public site cannot notify Slack or email. Copy the curl into your own environment with an API key when you want a live escalation.
{
"title": "Approve refund over $500?",
"context": "Customer #1042 requests a $750 refund. Order history attached.",
"options": [
{
"id": "approve",
"label": "Approve"
},
{
"id": "deny",
"label": "Deny"
}
],
"fields": [
{
"name": "note",
"type": "text",
"label": "Note"
}
],
"channels": [
{
"type": "email",
"to": "ops@example.com"
}
],
"ttl_seconds": 7200
}Run replays the documented success envelope. It does not hit /api/internal/ping-human.
Static contract preview. The public playground never calls the gateway and never opens a live escalation.
Why PingHuman
Agent escalations
POST title, context, optional choices, and 1 to 3 notification channels. Get poll_url back.
Slack and email notify
Notifications carry title plus a magic link. Private context never leaves the reply page.
Single-use reply tokens
256-bit capabilities stored only as SHA-256 hashes. Expired links return 410. Races return 409.
Poll or callback
GET the owner-scoped poll URL, or supply a callback for HMAC-signed resolve and expiry events.
Signed deliveries
x-pinghuman-signature is hex HMAC-SHA256 of the body. Retries fire immediately, then +30s and +5min.
Owner-scoped reads
Unknown IDs and non-owners both get 404. Slack webhooks must be hooks.slack.com. Callbacks are SSRF-guarded.
/api/v1/ping-human
Create escalation
Notify Slack or email with a magic link. Returns 201 with poll_url and poll_interval_seconds.
Poll status
Owner-scoped. Cache-Control no-store. Includes the human response when resolved.
| Parameter | Type | Required | Description |
|---|---|---|---|
| title | string | yes | 1 to 200 characters. Shown in notifications. |
| context | string | yes | 1 to 8000 characters. Reply page only. Always escaped. |
| options | array | no | 2 to 6 {id, label} choices. Omit for a plain acknowledge. |
| fields | array | no | Up to 5 {name, type: text|number, label?, required?} inputs. |
| channels | array | yes | 1 to 3 slack webhook_url (hooks.slack.com) or email to. |
| ttl_seconds | integer | no | Lifetime 60 to 86400. Default 3600. |
| callback | object | no | {url, secret 16-128}. URL is SSRF-guarded. Secret encrypted at rest. |
DELETE /api/v1/ping-human/escalations/:id cancels a pending or notified escalation. GET/POST /reply/:token is the public HTML reply surface.
Error reference
Invalid title, context, channels, Slack host, or an SSRF-blocked callback URL.
Missing gateway identity or invalid API key. Send x-api-key or api_key with agent routes.
Unknown escalation, not the owner, unknown reply token, or unknown path. Lookups do not leak existence.
Already resolved or cancelled, or another caller won the single-use reply race.
The magic-link reply token expired. The reply page renders HTML, not JSON.
Create 60, poll 1200, or reply 10 per 15 minutes. retryAfter is in seconds.
A callback was supplied but PINGHUMAN_ENC_KEY is not configured.
Example error response
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Not found"
},
"correlationId": "req_error123"
}FAQ
POST /escalations returns poll_url and poll_interval_seconds. GET that URL until status is resolved, expired, or cancelled, or supply a callback URL for an HMAC-signed webhook.
Notifications include the title and the reply link only. The private context field is rendered on the reply page and is always escaped. It never leaves that page.
No. Escalations are owner-scoped. Unknown IDs and non-owners both receive 404 with no existence leak. Reply tokens are 256-bit capabilities stored only as SHA-256 hashes.
Compare x-pinghuman-signature to hex HMAC-SHA256 of the JSON body using your callback secret. Also check x-pinghuman-timestamp within a 5 minute window. Retries fire immediately, then at +30s and +5min.
Send your Datpaq API key as an x-api-key header or an api_key query parameter. Keys are created in the Datpaq dashboard and a free tier is included. The public reply page is a single-use capability, not an API-key route.
POST an escalation, notify Slack or email with a magic link, then poll or receive an HMAC-signed callback when a person decides.