API reference

Ringba-compatible ping

A single-step ping URL per publisher lane that takes Ringba's parameters and answers in Ringba's field names.

A publisher already integrated with another platform has a system that pings one URL, with its credential in the path, and expects a price and a number back in a single answer. This door speaks that dialect. One request runs the auction and claims the winning bid, and the answer uses field names their platform already parses. The background is in Ringba-compatible ping; the native two-step protocol, which is better in every way you can control, is RTB ping and post.

It is a dialect, not a second engine. The same auction runs, the same bid rows are written, the same call and postback key are minted, and every request lands in the same ping ledger. What a publisher gets through this door and what they would get through the native one differ only in spelling.

The URL is the credential

GET or POST
https://api.buy3.io/api/rtb/compat/ringba/:token.json
  • :token is the lane's compatibility token, minted in the console for one publisher on one campaign. A trailing .json is ignored, because that is how these URLs are usually written.
  • It is separate from the publisher key, so the URL can be pasted into somebody else's platform without handing over the key, and either can be rotated on its own.
  • Rotating the publisher key moves the URL to its successor rather than breaking it.
  • The door is off until it is switched on for that key. A real token on a switched-off lane answers 403 compat_disabled.
  • The key's protocol setting is deliberately not consulted — this door has its own switch. Its address allowlist, its rate limits and its signature requirement all are.

One request, two steps

Behind the door, a request runs the ping and then immediately claims the bid it won. That has one consequence worth planning for: a 200 with a bidAmount means the caller is already expected. The destination is held, the call row exists, and a caller who never arrives is a bid that expires against the publisher's record. Send the caller, or do not ping.

  • Parameter names are case-insensitiveCID, cid and Cid are one parameter.
  • A GET takes them in the query string. A POST takes them in a JSON body, the query string, or both; where the two disagree, the body wins.
  • A body is at most 32 KB.
  • publisherInboundCallId is the idempotency key. Without it, an Idempotency-Key header is honoured instead.
  • Every request — refused ones too — is a row in the ping ledger. The ledger records the door's name, never the token.

Parameters

ParameterMeaning
CIDThe caller's number, as ten digits, eleven digits or E.164.
zipcodeThe caller's ZIP code.
stateThe caller's state. Two letters drive state targeting.
exposeCallerIdWhether the caller's number may be passed to the buyer.
sipOkWhether you can take the call over SIP.
publisherInboundCallIdYour id for the call, and the idempotency key.
anything elseBecomes a tag on the call.
The full rules, with lengths and the flag spellings, are on each endpoint below.

What comes back

FieldTypeMeaning
bidIduuidThe bid, already claimed. On a no-bid this is the auction's id, or null.
bidAmountnumberDollars, not cents — what you are paid. It is never what the buyer pays. 0 means no bid.
expireInSecondsintegerHow long the destination is held.
bidExpireDTISO 8601The same moment as a timestamp.
bidExpireEpochintegerThe same moment in milliseconds since 1970.
phoneNumber, phoneNumberNoPlusstringWhere to send the caller, with and without the leading plus. It is the lane's own tracking number when it has one, else the campaign's shared number, else the destination the claim returned.
sipAddressstringWhere to send the caller over SIP. Present only when you sent sipOk and a SIP domain is configured.
bidTermsobject[]{ code, message } — what the payout depends on. See below.
warningsobject[]{ code, description }. Advisory only: a warning never changes the outcome. Code 250 means the bid won but the lane has no number or SIP address to send the caller to — nobody can be delivered until that is fixed.
callId, refuuid, stringBeyond the dialect, and safe for a client that does not know them to ignore. They are the handles a support conversation starts from.
auctionIduuidThe auction, for the ping ledger.
postbackobject{ url, key } — the per-call conversion postback, the same one the native protocol returns.
rejectReasonstringOn a no-bid only: the reason and its code in one string, because that is the one field these platforms show an operator.
bidTerms codeMeans
101The call must connect.
100The call must last at least the stated number of seconds. message names it.
102The call must be marked converted.
110A duplicate caller inside the stated window is not paid.

A no-bid is a 200

As the dialect expects. rejectReason reads "<description> (Code: <code>)", and the code is one of the reject codes — numbers that never change meaning. That includes the two cases peculiar to a single-step door: a claim that lost its capacity between the two halves of the request (code 1000), and a publisher lane that is at its concurrency limit (code 1013).

Three refusals are not a bid of zero, because a client that ignores them will keep making the same mistake:

StatusBodyWhen
409The no-bid shape, (Code: 1025) or (Code: 1003)An identical request is still being scored, or that caller already has a live bid on this campaign.
429The no-bid shape, (Code: 1024), plus Retry-AfterThe key is over one of its rate limits.
400, 401, 403{ ok: false, error, message }The request could not be parsed, or the door refused it. A bad token, a switched-off URL or an address off the allowlist is an error, not a price of zero.

Rate limits

The publisher key's own per-minute, per-hour and per-day limits apply. Every answer carries RateLimit-Policy with all three windows and RateLimit with what is left of the current minute; a 429 adds Retry-After in seconds. The defaults are in Limits.

Endpoints

Ping and claim, with query parameters

GET/api/rtb/compat/ringba/:token

Runs the auction and claims the winning bid in one request, with the parameters in the query string. This is the form most platforms send. A win reserves the destination and creates the call, so send the caller. Every request writes a ping-ledger row for both sides to read; a win also writes the bid and the call.

No API key. No Authorization header. The request authenticates itself with a value in its body or URL, described below.

Path parameters

NameTypeDescription
tokenRequiredstringThe lane's compatibility token. A trailing .json is ignored.8–128 characters of letters, digits, - and _

Query parameters

NameTypeDescription
CIDOptionalstringThe caller's number. Ten digits, eleven digits or E.164 are all accepted. A campaign may require one, and a bid made without one carries a warning.up to 32 characters
zipcodeOptionalstringThe caller's ZIP code. It is kept on the call and passed to buyers that ask for it.up to 12 characters
stateOptionalstringThe caller's state. A two-letter code drives state targeting; anything else is kept as a tag called state rather than refused, because it is still something you said about the caller.up to 40 characters
exposeCallerIdOptionalstringWhether the caller's number may be passed on to the buyer.yes/no, true/false, 1/0, on/off or y/n
sipOkOptionalstringWhether you can take the call over SIP. When you can, and a SIP domain is configured, the answer may carry a sipAddress.the same flag spellings as exposeCallerId
publisherInboundCallIdOptionalstringYour own id for the inbound call — and the idempotency key. Send it: a retried request replays the first answer byte for byte instead of selling one caller twice.up to 120 characters
anything elseOptionalscalarKept as a tag on the call, with the source publisher. This is where sub_id, a keyword or a campaign name goes, and it is what tag filters and tag: reports read.at most 40 tags · key up to 64 characters, value up to 512

Example request

curl "https://api.buy3.io/api/rtb/compat/ringba/9f2a61c07be34d5580aa1c9e2d7f4b6e.json?CID=4155550142&state=CA&zipcode=94103&publisherInboundCallId=nw-88231&sub_id=fb-42"

Responses

  • 200A bid, already claimed. Send the caller to phoneNumber before bidExpireDT.
  • 200 (no bid)No bid. bidAmount is 0 and rejectReason carries the reason and its code.
{
  "bidId": "7c6b5a49-3827-4615-9048-372615049382",
  "bidAmount": 27.5,
  "expireInSeconds": 30,
  "bidExpireDT": "2026-09-20T14:03:41.000Z",
  "bidExpireEpoch": 1789913021000,
  "phoneNumber": "+18885550100",
  "phoneNumberNoPlus": "18885550100",
  "bidTerms": [
    {
      "code": 101,
      "message": "Call must connect"
    },
    {
      "code": 100,
      "message": "Minimum connected duration 90 seconds"
    }
  ],
  "warnings": [],
  "callId": "0b9f6c1e-52a4-4a0e-9f0a-3d1c7e8b2a11",
  "ref": "CA-482137",
  "auctionId": "3f2e1d0c-9b8a-4765-8432-10fedcba9876",
  "postback": {
    "url": "https://api.example.com/api/rtb/v1/conversion",
    "key": "b3p_4f19c2a70e5b8d63"
  }
}

Errors

StatusCodeWhen
400malformed_requestA POST body was sent and it is not valid JSON. Query parameters are still read on a GET, so this only reaches a POST.
401invalid_keyThe token in the path is not 8–128 characters of letters, digits, - and _, or it is not a token this platform knows, or the key behind it has been revoked and its grace window is over.
401signature_missingThe key requires signed requests and one of X-Buy3-Timestamp, X-Buy3-Nonce or X-Buy3-Signature was absent. The body also carries code: 4000.
401signature_invalidThe signature did not match. code: 4001.
401signature_staleThe timestamp is more than five minutes from ours. code: 4002.
401nonce_replayThat nonce has been used already. code: 4003.
403compat_disabledThe token is real but the single-step URL is switched off for that lane. This is deliberately distinguishable from an unknown token: somebody reading the ping ledger has to be able to tell "wrong URL" from "you turned this off".
403publisher_not_liveThe publisher is not live.
403campaign_not_liveThe campaign is not live.
403ip_not_allowedThe request came from an address that is not on the key's allowlist.
409(no-bid shape)An identical request is still being scored (1025), or that caller already holds a live bid on this campaign (1003). Wait rather than sending it again.
429(no-bid shape)The key is over one of its rate limits (1024). Retry-After says how long to wait.

Ping and claim, with a JSON body

POST/api/rtb/compat/ringba/:token

Exactly the same request, the same parameters and the same answers as the GET, with the parameters in a JSON body instead. A query string may be sent as well; where the two name the same parameter, the body wins. Use this form when a value would be awkward in a URL.

No API key. No Authorization header. The request authenticates itself with a value in its body or URL, described below.

Path parameters

NameTypeDescription
tokenRequiredstringThe lane's compatibility token. A trailing .json is ignored.8–128 characters of letters, digits, - and _

Request body

NameTypeDescription
CIDOptionalstringThe caller's number. Ten digits, eleven digits or E.164 are all accepted. A campaign may require one, and a bid made without one carries a warning.up to 32 characters
zipcodeOptionalstringThe caller's ZIP code. It is kept on the call and passed to buyers that ask for it.up to 12 characters
stateOptionalstringThe caller's state. A two-letter code drives state targeting; anything else is kept as a tag called state rather than refused, because it is still something you said about the caller.up to 40 characters
exposeCallerIdOptionalstringWhether the caller's number may be passed on to the buyer.yes/no, true/false, 1/0, on/off or y/n
sipOkOptionalstringWhether you can take the call over SIP. When you can, and a SIP domain is configured, the answer may carry a sipAddress.the same flag spellings as exposeCallerId
publisherInboundCallIdOptionalstringYour own id for the inbound call — and the idempotency key. Send it: a retried request replays the first answer byte for byte instead of selling one caller twice.up to 120 characters
anything elseOptionalscalarKept as a tag on the call, with the source publisher. This is where sub_id, a keyword or a campaign name goes, and it is what tag filters and tag: reports read.at most 40 tags · key up to 64 characters, value up to 512

Example request

curl -X POST "https://api.buy3.io/api/rtb/compat/ringba/9f2a61c07be34d5580aa1c9e2d7f4b6e.json" \
  -H "Content-Type: application/json" \
  -d '{
    "CID": "4155550142",
    "state": "CA",
    "zipcode": "94103",
    "publisherInboundCallId": "nw-88231",
    "sub_id": "fb-42"
  }'

Responses

  • 200A bid, already claimed. The warnings list is where an integration problem shows up before it becomes a support ticket — here, a lane with nowhere to send the caller.
  • 200 (no bid)No bid, in the same shape as on the GET.
  • 400 (bad body)The body could not be parsed. This is the platform's own envelope, not a bid of zero.
{
  "bidId": "7c6b5a49-3827-4615-9048-372615049382",
  "bidAmount": 27.5,
  "expireInSeconds": 30,
  "bidExpireDT": "2026-09-20T14:03:41.000Z",
  "bidExpireEpoch": 1789913021000,
  "bidTerms": [
    {
      "code": 101,
      "message": "Call must connect"
    },
    {
      "code": 100,
      "message": "Minimum connected duration 90 seconds"
    }
  ],
  "warnings": [
    {
      "code": 250,
      "description": "The bid was won but this lane has no number or SIP address to send the caller to — ask your account manager to attach one"
    }
  ],
  "callId": "0b9f6c1e-52a4-4a0e-9f0a-3d1c7e8b2a11",
  "ref": "CA-482137",
  "auctionId": "3f2e1d0c-9b8a-4765-8432-10fedcba9876",
  "postback": {
    "url": "https://api.example.com/api/rtb/v1/conversion",
    "key": "b3p_4f19c2a70e5b8d63"
  }
}

Errors

StatusCodeWhen
400malformed_requestA POST body was sent and it is not valid JSON. Query parameters are still read on a GET, so this only reaches a POST.
401invalid_keyThe token in the path is not 8–128 characters of letters, digits, - and _, or it is not a token this platform knows, or the key behind it has been revoked and its grace window is over.
401signature_missingThe key requires signed requests and one of X-Buy3-Timestamp, X-Buy3-Nonce or X-Buy3-Signature was absent. The body also carries code: 4000.
401signature_invalidThe signature did not match. code: 4001.
401signature_staleThe timestamp is more than five minutes from ours. code: 4002.
401nonce_replayThat nonce has been used already. code: 4003.
403compat_disabledThe token is real but the single-step URL is switched off for that lane. This is deliberately distinguishable from an unknown token: somebody reading the ping ledger has to be able to tell "wrong URL" from "you turned this off".
403publisher_not_liveThe publisher is not live.
403campaign_not_liveThe campaign is not live.
403ip_not_allowedThe request came from an address that is not on the key's allowlist.
409(no-bid shape)An identical request is still being scored (1025), or that caller already holds a live bid on this campaign (1003).
429(no-bid shape)The key is over one of its rate limits (1024). Retry-After says how long to wait.