Get Snapshot Status
curl --request GET \
--url https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference} \
--header 'Authorization: Bearer <token>'import requests
url = "https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyCampaigns API
Get Snapshot Status
Poll upload, processing, counts, and safe failure state
GET
/
external-api
/
v1
/
campaigns
/
{apiReference}
/
snapshots
/
{snapshotReference}
Get Snapshot Status
curl --request GET \
--url https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference} \
--header 'Authorization: Bearer <token>'import requests
url = "https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://getbill.io/external-api/v1/campaigns/{apiReference}/snapshots/{snapshotReference}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyAuthentication
Requiresdebts:read or debts:write. Uses the read limiter: 1,000 requests/hour per company.
string
required
Your campaign reference.
string
required
The client-created snapshot reference used to submit or start this snapshot.
curl "https://getbill.io/external-api/v1/campaigns/client-a-2026/snapshots/export-2026-07-17-550e8400" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
200
{
"error": false,
"message": "Success",
"data": {
"api_reference": "client-a-2026",
"snapshot_reference": "export-2026-07-17-550e8400",
"delivery_mode": "staged",
"status": "completed",
"core_applied": true,
"expected_row_count": 2500,
"received_row_count": 2500,
"received_chunk_count": 3,
"next_chunk_index": 3,
"counts": {
"created": 12,
"updated": 2488,
"resolved": 7,
"resurrected": 2,
"retained": 2486
},
"failure": null,
"warning_count": 1,
"warnings_omitted": 0,
"warnings": [
{
"row_number": 17,
"code": "expensive_destination_not_accepted",
"message": "Debt accepted; phone communications restricted for an expensive destination.",
"field": "phone",
"blocked_channels": ["sms", "rcs", "call", "whatsapp", "voicemail"]
}
],
"enrichment": {
"civility_detection": {
"enabled": true,
"eligible": 82,
"processed": 82,
"already_processed": 410,
"skipped": 0,
"credits_charged": 1.0,
"skip_reason": null
},
"email_validation": {
"enabled": true,
"eligible": 20,
"processed": 18,
"already_processed": 474,
"skipped": 0,
"credits_charged": 3.6,
"skip_reason": null
}
},
"created_at": "2026-07-17T09:00:00Z",
"updated_at": "2026-07-17T09:04:12Z"
}
}
Status handling
After202 Accepted, poll this endpoint. After a network timeout on a mutation, retry the identical request body; if status is failed, correct the source and submit a new reference; if it is processing_error, do not resubmit and contact GetBill support.
| Status | Meaning | Action |
|---|---|---|
uploading | Staged upload open | Resume at next_chunk_index |
pending | Queued | Poll with backoff |
processing | Worker active | Poll with backoff |
completed | Fully complete | Read counts |
failed | Core not applied | Read failure; correct and use a new reference |
processing_error | Core applied; post-processing recovery required | Stop and contact GetBill support |
counts is null before core application. counts.resolved is the number of debts treated as settled because they were absent from the snapshot. failure is null or contains only reason plus optional one-based row and field. core_applied: true means debt upsert and missing-debt reconciliation committed atomically; do not interpret processing_error as a rollback.
warnings is a safe, capped list of non-blocking row outcomes available only after asynchronous processing. warning_count is its total, and warnings_omitted is the number excluded after the first 100. A costly phone destination not allowed by the GetBill campaign configuration is a warning: the row remains in the snapshot, email and postal reminders may continue, and only SMS, RCS, calls, WhatsApp, and voicemail are blocked for that phone.
enrichment is null until the worker reaches the enrichment stage. It contains only aggregate counts and safe skip reasons such as feature_disabled, insufficient_credits, and provider_unavailable; it never exposes debt IDs, names, email addresses, fingerprints, or provider payloads. Campaign enrichment settings are captured when the snapshot session starts, so later dashboard edits affect only later snapshots. Manual imports keep their own explicit enrichment choices.
Missing and cross-company references both return 404.