The ping ledger

Every ping in and out is a row you can open: the request, the answer, the latency and why it ended the way it did — for you, and for each publisher on their own side.

After this page you can find any ping by its reference, read what was actually sent and answered, tell a slow buyer from a badly filtered publisher, and export the evidence for a conversation with either.

On most platforms a no-bid is a number on a dashboard. Here every ping is a ledger row: what was sent, what came back, how long it took and why it ended the way it did. It is under Ping log in the console and in the Pings API.

Two ledgers

LedgerConsoleOne row is
InboundIncoming · from publishersOne request a publisher made to you — an auction, whatever it decided.
OutboundOutgoing · to buyersOne request you made to one buyer's bidding endpoint. A single auction that asked three buyers is three rows here and one row there.
They have different columns, and the API takes direction=inbound or direction=outbound. Inbound is the default.

A third kind of record sits beside the inbound ledger: requests refused before an auction existed — a bad signature, an address off the allowlist, a key on the wrong surface. They have no auction to belong to and are counted separately, because they are the refusals a publisher can most often fix themselves.

What an inbound row holds

Find every ping refused for the wrong state
curl "https://api.buy3.io/api/v1/pings?direction=inbound&outcome=no_bid&reasonCode=1008&from=2026-09-19T05:00:00Z" \
  -H "Authorization: Bearer $BUY3_API_KEY"
One row
{
  "id": "3f2e1d0c-9b8a-4765-8432-10fedcba9876",
  "ref": "AU-100483",
  "at": "2026-09-20T14:03:11.000Z",
  "outcome": "no_bid",
  "reason": {
    "code": 1008,
    "reason": "state_not_targeted",
    "sentence": "That state is not being bought."
  },
  "campaign": { "id": "6a2d1f0e-8b7c-4c55-a1d3-0e9f8a7b6c5d", "name": "Acme Health inbound" },
  "publisher": { "id": "c4e1a2b3-9d8f-4f6e-b5a4-1c2d3e4f5a6b", "name": "Northwind Media" },
  "callerNumber": "••••••0142",
  "callerState": "AR",
  "payoutCents": 0,
  "clearingPriceCents": null,
  "winningTarget": null,
  "targetsSolicited": 0,
  "bidsReceived": 0,
  "elapsedMs": 19,
  "statusCode": 200
}
ColumnWhat it shows
AuctionThe public reference, such as AU-100483. It is what you and the publisher both quote.
PublisherWho asked.
CampaignWhich campaign they asked about. The key decides it, so it is never in the request.
CallerMasked to the last four digits unless the campaign discloses caller ID.
AnswerThe outcome — see the table below.
WhyFor anything but a win, the reject code and a sentence written for the person reading it.
Payout offeredWhat you quoted the publisher, when you bid.
TookMilliseconds, from the request arriving to the answer leaving.
OutcomeMeans
wonYou bid, and the reservation was taken.
no_bidYou did not bid. The reason is on the row.
cachedThe publisher repeated a request they already held a live bid for, and were given the same bid rather than a second reservation.
rate_limitedOver the key's limit. Answered 429.
blockedRefused before scoring: a suppressed caller, or an identical request already in flight.
errorSomething on this side failed. Worth raising.

What an outbound row holds

An outbound row records one ask of one buyer: the request as it was sent — after macros were filled in — the buyer's raw answer, the HTTP status, the latency, what your response paths read out of it, and whether that bid went on to win.

StatusMeans
bidThey priced the call.
no_bid · rejectedThey declined it, with whatever reason they gave.
timeoutThey did not answer inside the campaign's ping budget and were excluded from that auction.
errorTheir endpoint failed, or answered something unreadable.
won · claimedTheir bid won, and the caller was sent to them.
lostAnother target took the call. The loss code says why.
expiredThe bid stood and the publisher never sent the caller.
voidThe caller went away before delivery.

Reading one ping

Opening an inbound ping shows its trace — the same idea as a call's waterfall, for the auction that priced it. The page is laid out as When and Took, then What happened, then Details, the Tags the publisher sent, The call this became, and finally the two bodies.

  • What happened is the outcome in words: whether a cached bid was reused, which filters ran, which targets were candidates and why the others were skipped, which buyers were pinged and which timed out, how the bids ranked, and the reservation taken for the winner.
  • Details carries the publisher's own reference, their id for the call, the address the request came from, the user agent, whether they said they could take SIP, and the quote's expiry.
  • Tags the publisher sent is labelled unverified on the page, because a publisher can put anything in a ping. Treat it as a claim, not a fact.
  • What the publisher sent and What we answered are the two bodies exactly as they crossed the wire — which is the point of the page. A tidied version would make the one argument this log exists to settle unwinnable.
  • A won ping links to the call it became, once the caller arrives.

The summary

The same window, rolled up — the screen for "why is my fill rate what it is" rather than "what happened to that ping".

curl
curl "https://api.buy3.io/api/tracking/pings/summary?from=2026-09-19T05:00:00Z&to=2026-09-20T05:00:00Z" \
  -H "Authorization: Bearer $BUY3_SESSION_TOKEN"
SectionWhat it answers
InboundPings received, how many you bid on, the win rate, how fast we answer as a median and a 95th percentile, and the payout offered. A mean would hide exactly the slow tail that loses auctions.
No-bid reasonsEvery refusal ranked, with its share and its sentence. The top row is usually the whole story.
TargetsPer buyer endpoint: pings, bids, declines, timeouts, errors, median and 95th-percentile latency, and the average bid. This is the table that names the buyer costing every auction its budget.
PublishersPer publisher: pings, wins, and how many of those wins became a call.

The outbound summary answers the mirror-image question: pings sent, how many came back with a bid, how many won the call, and how many timed out or errored. A buyer who times out on a fifth of your auctions is not a buyer who bids low; they are a buyer who is not in the auction at all.

Filters, windows and retention

  • Filter by campaign, publisher, target, outcome or status, and by reject code — which is the fastest way from "our fill rate dropped" to the reason.
  • The window defaults to the last seven days, in the workspace's own days, and may span at most 92.
  • Rows are pruned after thirty days. Asking for a wider window is allowed and simply returns nothing older than that, so export anything you need to keep.
  • Calls keep the bid they were won on, so a call's own record outlives the ping that produced it.

Exporting

One ledger per file
curl -L "https://api.buy3.io/api/tracking/pings/export.csv?direction=inbound&from=2026-09-19T05:00:00Z" \
  -H "Authorization: Bearer $BUY3_SESSION_TOKEN" \
  -o pings-inbound.csv

The two directions export separately, because they have different columns and a file with half its cells empty is two files pretending. The inbound file carries the reference, the outcome, the reject code with its reason and sentence, the campaign and publisher, the caller and state, the latency and status, the payout offered and the clearing price, the winning target, and how many targets were asked and how many answered. The outbound file carries the bid, the auction it belonged to, the target and buyer, the status, the bid, the HTTP status and latency, the reject code and sentence, and the call it became.

Every export is written to the activity log before the first byte, with the direction, the filters, the window and the row count. The encoding, quoting and cap are the same as every other file the platform writes — see the file.

Who can read what

You read every ping in your workspace, in both directions. Each publisher, in the publisher portal, reads the pings they sent: their request, your answer and the reason, with a sentence and whose move it is. They never see your buyers' bids, the auction's trace, your margin or anybody else's traffic.

A worked example

Fill on Acme Health inbound drops from about a quarter to under a tenth over a weekend.

  1. Open the summary for the last three days, inbound. Pings received are flat; the win rate has halved.
  2. Read the no-bid reasons. 1003 no_capacity has gone from a tenth of refusals to over half. That is a demand problem, not a supply one.
  3. Switch to the targets table. One buyer's timeout rate has gone from 2 per cent to 34, with a 95th-percentile latency far over the campaign's budget. They are being excluded from most auctions.
  4. Open one outbound row on that target. The request is exactly what it always was; the answer is empty and the latency sits on the budget. It is their endpoint, not your template.
  5. Export the inbound ledger for the window and send the buyer their own numbers alongside the dates.
  6. Meanwhile, check the publishers table. Northwind's won-to-call rate is 96 per cent — they are not the problem, and telling them so is worth as much as fixing the buyer.

Next steps