Authentication
The API is open. You receive a secret token (e.g. pb_xxxxxxxx) at listener creation; you use it as the t query parameter for all subsequent operations on that listener.
Keep your token private. Anyone with it can read all hits on your listener. Treat it like an API key.
Base URL
https://pingback.sh/api
Rate limits
| Endpoint | Limit |
|---|---|
| POST /generate.php | 200 listeners / hour / IP |
| GET /feed.php | 600 requests / hour / token |
| POST /wipe.php | 10 / day / token |
Rate-limited requests return HTTP 429 with {"error": "Rate limit exceeded..."}.
Error format
Errors are JSON with an error field and the appropriate HTTP code:
{ "error": "Invalid token" }
| HTTP | Meaning |
|---|---|
| 400 | Bad request (invalid JSON, missing required field) |
| 401 | Missing or invalid token |
| 404 | Listener not found / expired |
| 405 | Wrong HTTP method |
| 429 | Rate limit exceeded |
| 500 | Server error |
Endpoints
POST
/api/generate.php
Creates a new listener and returns ready-to-use payloads + secret token.
Request body (JSON, all optional)
| Field | Type | Description |
|---|---|---|
| emailopt | string | Notification email on every hit |
| discord_webhookopt | string | Discord webhook URL for rich notifications |
| labelopt | string | Private label (max 64 chars) — helps you remember which test this listener belongs to |
Example request
curl -X POST https://pingback.sh/api/generate.php \ -H 'Content-Type: application/json' \ -d '{"email":"you@example.com","label":"h1-acme"}'
Example response (200)
{
"subdomain": "k7m3pq9x",
"full_host": "k7m3pq9x.pingback.sh",
"http_url": "https://k7m3pq9x.pingback.sh/",
"dns_target": "k7m3pq9x.pingback.sh",
"xss_payload": "\">",
"secret_token": "pb_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"dashboard": "https://pingback.sh/dashboard?t=pb_xxx...",
"expires_at": "2026-06-22 12:00:00"
}
GET
/api/feed.php?t=YOUR_TOKEN&since=0
Fetch up to 100 most recent hits, optionally newer than a hit id (for polling).
Query parameters
| Param | Type | Description |
|---|---|---|
| treq | string | Your secret token |
| sinceopt | integer | Return only hits with id > since (use 0 to get latest 100) |
Example request
curl 'https://pingback.sh/api/feed.php?t=pb_xxx&since=0'
Example response (200)
{
"hits": [
{
"id": 42,
"protocol": "http",
"source_ip": "203.0.113.42",
"country": "US",
"asn": "AS15169 Google LLC",
"http_method": "GET",
"http_path": "/admin?from=10.0.0.5",
"user_agent": "curl/8.5",
"captured_at": "2026-05-24 14:32:08",
/* ... full hit fields */
}
],
"total": 42
}
Fields by protocol
| Protocol | Populated fields |
|---|---|
| http / https | http_method, http_host, http_path, http_query, http_headers, http_body, user_agent, raw_request |
| dns | dns_query, dns_type, dns_resolver |
| xss | xss_url, xss_referrer, xss_cookies, xss_dom, xss_localstorage |
| smtp | smtp_from, smtp_to, smtp_subject, smtp_body, raw_request |
Polling tip: save the highest
id from each response and pass it as since in the next request to receive only new hits.
POST
/api/wipe.php?t=YOUR_TOKEN
Permanently deletes the listener and all its captured hits. Cannot be undone.
Example
curl -X POST 'https://pingback.sh/api/wipe.php?t=pb_xxx'
Response (200)
{ "ok": true }
Code samples
curl
# 1. Create listener RESP=$(curl -s -X POST https://pingback.sh/api/generate.php \ -H 'Content-Type: application/json' \ -d '{"email":"you@example.com"}') TOKEN=$(echo $RESP | jq -r .secret_token) HOST=$(echo $RESP | jq -r .full_host) echo "Listener: $HOST" # 2. Use the payload (drop $HOST in your bug bounty payloads) echo "Use: https://$HOST/ or anything@$HOST" # 3. Poll the feed SINCE=0 while true; do curl -s "https://pingback.sh/api/feed.php?t=$TOKEN&since=$SINCE" | jq . SINCE=$(curl -s "https://pingback.sh/api/feed.php?t=$TOKEN&since=$SINCE" | jq -r '.hits[0].id // 0') sleep 5 done
Python
import requests, time # 1. Generate r = requests.post("https://pingback.sh/api/generate.php", json={"email": "you@example.com", "label": "h1-acme"}) data = r.json() token = data["secret_token"] host = data["full_host"] print(f"Listener: {host}") # 2. Poll since = 0 while True: r = requests.get(f"https://pingback.sh/api/feed.php", params={"t": token, "since": since}) hits = r.json()["hits"] for h in hits: print(h["protocol"], h["source_ip"], h.get("http_path", "")) if hits: since = hits[0]["id"] time.sleep(5)
Node.js
const base = 'https://pingback.sh'; const r = await fetch(`${base}/api/generate.php`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'you@example.com', label: 'h1-acme' }) }); const { secret_token, full_host } = await r.json(); console.log(`Listener: ${full_host}`); let since = 0; while (true) { const r2 = await fetch(`${base}/api/feed.php?t=${secret_token}&since=${since}`); const { hits } = await r2.json(); for (const h of hits) console.log(h.protocol, h.source_ip, h.http_path); if (hits.length) since = hits[0].id; await new Promise(r => setTimeout(r, 5000)); }
Go
resp, _ := http.Post(
"https://pingback.sh/api/generate.php",
"application/json",
bytes.NewReader([]byte(`{"email":"you@example.com"}`)),
)
var g struct {
SecretToken string `json:"secret_token"`
FullHost string `json:"full_host"`
}
json.NewDecoder(resp.Body).Decode(&g)
fmt.Printf("Listener: %s\n", g.FullHost)
since := 0
for {
r, _ := http.Get(fmt.Sprintf("https://pingback.sh/api/feed.php?t=%s&since=%d", g.SecretToken, since))
// parse r.Body, update since, sleep 5s
time.Sleep(5 * time.Second)
}