API reference

REST endpoints for automating listener creation, polling hits, and integrating pingback.sh into your own workflows.

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

EndpointLimit
POST /generate.php200 listeners / hour / IP
GET /feed.php600 requests / hour / token
POST /wipe.php10 / 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" }
HTTPMeaning
400Bad request (invalid JSON, missing required field)
401Missing or invalid token
404Listener not found / expired
405Wrong HTTP method
429Rate limit exceeded
500Server error

Endpoints

POST /api/generate.php

Creates a new listener and returns ready-to-use payloads + secret token.

Request body (JSON, all optional)

FieldTypeDescription
emailoptstringNotification email on every hit
discord_webhookoptstringDiscord webhook URL for rich notifications
labeloptstringPrivate 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

ParamTypeDescription
treqstringYour secret token
sinceoptintegerReturn 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

ProtocolPopulated fields
http / httpshttp_method, http_host, http_path, http_query, http_headers, http_body, user_agent, raw_request
dnsdns_query, dns_type, dns_resolver
xssxss_url, xss_referrer, xss_cookies, xss_dom, xss_localstorage
smtpsmtp_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)
}