Publisher integration guide
AffsSpace External RTB
Send a bid request, evaluate the response, and route an accepted caller to the returned destination. The contract works with Ringba and any server-side call-routing platform that supports HTTPS and JSON.
Quick start
- 01
Get access
Receive an API key and Program ID from AffsSpace.
- 02
Send a bid
POST the caller ZIP and original caller ID to the Program endpoint.
- 03
Check accepted
Read the accepted field; HTTP 200 alone is not an accepted bid.
- 04
Route the caller
For accepted bids, route the same caller to destination.
API request
Each Program has a unique ID supplied by AffsSpace. Put it in the URL; do not send it again in the JSON body.
Endpoint
POST https://rtb.affs.space/api/v1/rtb/programs/{programId}/bidExample for Program 12018: https://rtb.affs.space/api/v1/rtb/programs/12018/bid
Authentication and headers
- API key
- X-API-Key: <YOUR_API_KEY>
- Content-Type
- application/json
- Idempotency-Key · optional, recommended
- Use 16–128 visible ASCII characters. Reuse the key only when safely retrying the exact same request. Omit it for an independent request; headerless requests use only the short active-caller safety window and do not create a permanent idempotency identity.
Store API keys only in your server or call-routing platform. Never embed them in browser JavaScript.
{
"zip_code": "90710",
"caller_id": "+12025550123"
}zip_code must be a five-digit US ZIP Code.
caller_idis the caller's US phone number / ANI. Ten digits or a leading US country code are accepted, with common punctuation.
curl -X POST \
"https://rtb.affs.space/api/v1/rtb/programs/12018/bid" \
-H "X-API-Key: <YOUR_API_KEY>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: request-12345-abc" \
-d '{
"zip_code": "90710",
"caller_id": "+12025550123"
}'API response
A valid request may return HTTP 200 with accepted=false. Always evaluate accepted before routing.
{
"accepted": true,
"bidId": "AFB_SAMPLE_BID_IDENTIFIER",
"bidAmount": 42.75,
"billableDuration": 100,
"destination": "+13105550123"
}Short-lived offers may additionally include expireInSeconds (remaining whole seconds) and bidExpireEpoch (absolute Unix epoch milliseconds). When present, explicitly map expiry in your RTB platform and deliver the call before that deadline. Adding these response fields alone does not configure Ringba. Replays do not extend the deadline. The destination remains the static AffsSpace ingress; an accepted quote is not a completed call.
New single-request offers default to a 40-second lifetime after auction finalization. Initial claim authorization requires at least 10 seconds remaining, so deliver promptly within approximately 30 seconds. Explicit enrollment overrides and already-issued offers retain their timing. Two-request quotes allow up to 30 seconds, potentially less when the buyer quote expires sooner. These are arrival windows, not call durations.
- bidAmount
- Publisher-facing bid amount in USD.
- billableDuration
- Final duration requirement for this accepted bid, in seconds.
- destination
- Exact AffsSpace ingress to which the accepted physical caller must be routed.
- bidId
- AffsSpace identifier for support.
{
"accepted": false,
"rejectReason": "program_unavailable",
"retryable": false
}When accepted is false, do not route the call to an AffsSpace destination from that request.
rejectReason identifies the category and retryable indicates whether retrying is reasonable.
HTTP behavior
HTTP 200 carries the normal auction result, including a valid no-bid with accepted=false. HTTP 400 identifies an invalid request, HTTP 401 an invalid credential, HTTP 429 a bounded rate limit, and HTTP 503 a temporary infrastructure condition. Follow retryable and any Retry-After header; never infer acceptance from the HTTP status alone.
| Reason | Meaning |
|---|---|
| unauthorized | The API key is missing, malformed, or not accepted. |
| invalid_request | The JSON body or one of its fields is not accepted. |
| invalid_zip_code | zip_code is not a five-digit US ZIP Code. |
| invalid_caller_id | caller_id is not an accepted US phone number. |
| invalid_idempotency_key | Idempotency-Key does not satisfy the documented format. |
| publisher_inactive | The Publisher's External RTB profile is currently inactive. |
| publisher_disabled | The Publisher is currently paused. |
| program_inactive | The Program is currently paused. |
| publisher_program_inactive | The Publisher is not active for this Program. |
| program_unavailable | The Program cannot accept this request right now. |
| enrollment_not_ready | The Publisher enrollment is not ready to accept bids. |
| idempotency_conflict | The Idempotency-Key was already used with a different request payload. |
| idempotency_attempt_complete | That idempotent request already reached a terminal call state. |
| request_in_progress | The exact request is already being processed; retry as directed. |
| caller_attempt_in_progress | A request for this caller is already active; retry as directed. |
| conflicting_zip | An active request for this caller used a different ZIP Code and was not replaced. |
| active_offer_conflict | An existing offer prevents a second Buyer auction for this caller. |
| no_coverage | No bid is available for the submitted request. |
| buyer_duplicate_ping | The Buyer already received this bid request and did not return a new offer. |
| buyer_rate_limited | Buyer capacity is temporarily rate limited; follow retry guidance. |
| buyer_invalid_response | No usable Buyer response was available for this request. |
| margin_not_allowed | No Publisher-facing bid remained after the configured payout policy. |
| rate_limited | Request volume is temporarily limited; follow retry guidance. |
| temporarily_unavailable | A temporary service condition prevented a bid. |
Ringba setup
Create a Ring Tree Target and use JavaScript for all four response parsers. Ringba UI labels and ZIP-capture tags can vary by account configuration; use your existing ZIP and original-ANI variables.
Request settings
- Method
- POST
- URL
- https://rtb.affs.space/api/v1/rtb/programs/{programId}/bid
- Content type
- application/json
- HTTP header key
- X-API-Key
- HTTP header value
- <YOUR_API_KEY>
- Body
- zip_code: <Ringba ZIP variable>
caller_id: <Ringba original Caller ID / ANI variable>
Response parsing · JavaScript
Enable Dynamic Number/SIP on the Ring Tree Target, then add these four scripts and select JavaScript as the parsing type for each one. Use Ringba's Test Request to verify them against an accepted response in your account.
Bid Amount
input = JSON.parse(input);
return input.bidAmount;Acceptance
input = JSON.parse(input);
return input.accepted === true;Destination
input = JSON.parse(input);
return input.destination;Required Duration
input = JSON.parse(input);
return input.billableDuration;The Call Acceptance script returns true only when AffsSpace accepted the bid. A false value is a no-bid even though AffsSpace correctly returns HTTP 200. Use the Bid Amount script for Dynamic Bid Parsing, Required Duration for Dynamic Duration Parsing, and Destination for Dynamic Number/SIP Parsing.
destination and preserve the caller ID / ANI used in the bid request. Configure Ringba to use billableDurationfor that accepted bid's duration qualification and conversion tracking.Other platforms / custom integration
1. POST the Program endpoint.
2. Check accepted.
3. Read bid and duration, then route to destination or treat it as no bid.
response = POST(...)
if response.accepted:
bid = response.bidAmount
requiredDuration = response.billableDuration
routeCall(response.destination)
else:
noBid()Testing checklist
- ✓ Use a valid Program ID and API credential supplied by AffsSpace.
- ✓ Use a controlled caller ID and valid five-digit ZIP Code.
- ✓ Verify acceptance, bid, duration, and destination independently.
- ✓ Confirm accepted=false never routes to an AffsSpace destination.
- ✓ Place a controlled test call and preserve the original caller ANI.
- ✓ Verify the returned duration is used for qualification tracking.