Overview

Campaign snapshots let an integration synchronize the active debts of a campaign from the complete current source view. The scope is not fixed: a new valid reference creates a debt, attaches it to that campaign, and adds it to the configured collection timeline. Before implementing this workflow, see Understand Campaigns to distinguish the campaign’s durable scope from the point-in-time snapshot sent by the integration.
A snapshot describes the complete active scope after synchronization, including new debts that did not exist in earlier snapshots. When processing completes, a campaign debt absent from the snapshot is treated as settled. Never send a partial extract as a complete snapshot.

Choose the right workflow

How you send a payment plan depends on the scope synchronized by your integration and the identifier it has available. The two write contracts are alternatives. A complete campaign synchronization sends the payment plan in the relevant snapshot row. An individual operation separately targets a GetBill debt with /debts/{id}/payment-plan. Do not mix the two request shapes. For grouped debts, the GET endpoint returns the shared group view and does not guarantee read-back of every plan sent row by row in a snapshot. The source system remains the reference in that case. Your integration stores and sends only two identifiers that it owns:
  • api_reference: the stable campaign reference
  • snapshot_reference: a client-created, stable and unique reference for one complete source snapshot.
These are the only identifiers the integration needs for this workflow.

Generate a snapshot reference

Generate snapshot_reference in your integration when it creates a complete source snapshot. It must be unique within the campaign and contain 1 to 100 lowercase letters, digits, dots, underscores, or hyphens; it must start and end with a letter or digit. Use an immutable source export ID when you have one, or append a UUID. For example:
Do not use a date alone: two snapshots on the same day would conflict. Store the generated reference with the serialized request. Reuse it only to retry that exact snapshot after a timeout; every new or corrected snapshot needs a new reference.

One OAuth-authenticated GetBill company

Each OAuth access token authenticates one GetBill company for every lookup and mutation. Keep the campaign and snapshot references stable within that company. Campaign reads and snapshot status accept debts:read or debts:write. Provisioning and snapshot mutations require debts:write.
See OAuth Setup for the complete authentication flow.

Balance and payment-plan behavior

Accepted requests are applied in arrival order: the last accepted API call wins, even when an older source export arrives later. Do not send a source timestamp. Request receipt time, campaign locking, snapshot_reference, and the accepted body fingerprint provide chronology, serialization, and retry protection. remaining_amount is the current unpaid balance and can move down or up without a separate explanation of the source-side event. A present payment_plan replaces any active plan local to that debt when its amounts are consistent. Omitting payment_plan keeps the active local payment plan unchanged. Every installment with status set to paid requires paid_at and an external_payment_id that is unique for the authenticated integration and debt. The contract does not accept snapshot_at, allocations, financial_operations, coverage, or covered_remaining_amount. Keep those details in the source system.

Automated enrichment

Civility detection and email validation for automated snapshots are configured by a GetBill user on the campaign. Both options are disabled by default and are exposed read-only as automated_enrichment on campaign responses. The integration must not send detect_civility or validate_emails in snapshot requests. The settings are captured when a one-request or staged snapshot starts. Editing the campaign later does not change an in-flight snapshot and does not launch a backfill. Manual imports retain their own explicit choices and do not inherit the campaign settings. GetBill remembers the normalized first name and email processed for each debt. An unchanged value is not processed or billed again; a changed value becomes eligible again. Explicit civilities are never overwritten. Snapshot status exposes only aggregate enrichment counts and safe skip reasons.

Establish the campaign reference

An api_reference can be:
  • communicated out of band after a GetBill user assigns it to an existing campaign; or
  • created idempotently with Provision a Campaign.
References contain 1 to 100 lowercase ASCII letters, digits, dots, underscores, or hyphens. They must start and end with a letter or digit. Examples: finance-42, north.region_2026. API provisioning creates a campaign ready for configuration. Before sending snapshots, a GetBill user completes the campaign’s collection setup in GetBill and activates it. The integration sends references and snapshot rows; it does not configure collection behavior through this API. Poll Get a Campaign until:
Snapshot submission otherwise returns 409 with one of:
  • campaign_configuration_required when campaign setup is incomplete or has changed
  • campaign_not_active when the campaign is paused or completed
  • campaign_mode_not_supported when the campaign cannot accept snapshot synchronization; ask a GetBill administrator to configure it.

Choose a delivery mode

Only one snapshot may be submitted for a campaign at a time. A second reference returns snapshot_in_progress while the current snapshot is uploading, pending, or processing. A processing_error also blocks the campaign until operator or GetBill support recovery.

One-request delivery

  1. Send Submit a Snapshot.
  2. Save the Location response header or data.status_url.
  3. Poll Get Snapshot Status after the 202 response.

Staged delivery

  1. Start a Snapshot with the final row count.
  2. Upload chunks 0, 1, 2, and so on with Upload a Snapshot Chunk.
  3. Resume after a timeout from next_chunk_index returned by Get Snapshot Status.
  4. Finalize the Snapshot only after received_row_count equals expected_row_count.
  5. Poll status after 202.
Use Fail a Snapshot to abandon a staged upload before finalization. Pending or processing snapshots cannot be cancelled.

Choose the balance granularity

A campaign snapshot is the complete current view of open balances. It is the only data the integration sends for this workflow: do not send payment or credit-note events separately. Choose the representation that your source can export accurately, then keep that representation for the same receivables stream. Do not mix account-balance rows and invoice-balance rows for the same receivables. remaining_amount is always the current unpaid balance, never the original invoice amount. GetBill applies it directly and records the change through the import audit trail without requiring a reason. A new positive balance is both the opening debt amount and its remaining balance.

Invoice balance

Use one row for each invoice when the source exports the invoice’s own unpaid balance. Send invoice_reference alone and omit internal_id.

Account balance

Use one row for a debtor or account when the source exports only its total unpaid balance. Send internal_id alone and omit invoice_reference.
For an account balance, a daily sequence can look like this: If both fields are supplied, internal_id supplies the primary identity, and invoice_reference is also validated and must not belong to another debt. Integrations should normally send only the identifier for their chosen representation.
remaining_amount alone can represent a payment, credit, refund correction, write-off, fee, reversal, or reopening. The snapshot does not accept a second operation list or payment allocations to explain the change. Send payment_plan only when the plan projection must also change.

Snapshot row contract

Unknown fields are rejected. Every row requires:
  • internal_id, or invoice_reference when internal_id is absent
  • remaining_amount, as a non-negative JSON number with at most two decimals
  • currency, as an uppercase ISO 4217 code
  • either lastname or debtor_company. firstname is optional
  • at least one valid email or phone.
For a new debt, remaining_amount must be greater than zero. An existing debt may use zero. Matching is case-insensitive by internal_id, falling back to invoice_reference. Effective identities and invoice references must each be unique across the complete snapshot. Use only the fields listed above. Campaign setup, debt status, and payment events are not part of a snapshot row. The legacy accept_expensive_destination key is tolerated and ignored for campaign synchronization regardless of its value or JSON type. Inside metadata, the payment_plan key is reserved by GetBill and must not be sent. Invoice-per-debt example row:
The worker validates the complete staged snapshot before applying it. A pre-application validation failure sets the snapshot to failed; no row is upserted and no missing debt is reconciled.

Send an external payment plan

Add payment_plan to the row when a payment plan has been established in the connected system. Send every installment in that same row. No request per date is required. The payment plan applies only to the debt identified by that row. When a debtor has several grouped debts, each row keeps its own balance and payment plan.
For an active plan:
  • external_reference is required, non-empty, and limited to 100 characters
  • status must be active
  • installments is a non-empty array
  • each installment has a unique and stable external_reference limited to 100 characters, a positive amount with at most two decimals, a payment_date in YYYY-MM-DD format, and a status equal to pending or paid
  • the total of pending installments must equal remaining_amount. Otherwise, the snapshot is rejected with invalid_snapshot_row on the payment_plan field.
When an external payment plan is first sent for an existing debt, an installment may already have the paid status. Each already-paid installment must include paid_at and external_payment_id. The total of the pending installments alone must match the supplied balance. GetBill retains paid-installment history for audit without subtracting it from the supplied balance a second time. A paid installment may be sent on first observation. It must include the following payment details:
paid_at must be an ISO 8601 datetime with a timezone and no fractional seconds. external_payment_id identifies the payment idempotently, must be unique for the authenticated integration and debt, and is limited to 255 characters. Reuse it only for an exact replay of the same payment, including after plan replacement. A paid installment cannot return to pending. Its amount, payment_date, paid_at, and external_payment_id can no longer be changed. Omitting payment_plan keeps the active local payment plan unchanged. To cancel a payment plan sent by this integration, send the following object without installments. external_reference must match the active plan so a stale cancellation cannot cancel a newer schedule.
A present payment_plan replaces the active debt-local plan when its amounts are consistent, including a plan created locally, by the voice agent, or by another external flow. The replacement affects only the debt represented by that row. GetBill preserves paid installments and their transactions for audit. An identical snapshot or unchanged schedule can be replayed without recreating installments or transactions.

Empty snapshots

An empty snapshot treats every campaign debt that is not already settled as settled.

Idempotency and safe retries

Use one snapshot_reference per logical source snapshot. Reuse it only to retry that same snapshot; corrected data requires a new reference. See Generate a snapshot reference for a safe generation pattern. One-request retries are accepted only when the campaign and snapshot references, delivery mode, and exact request-body bytes are unchanged. GetBill stores a server-computed SHA-256 of the raw body; JSON with different whitespace or key order conflicts even when it decodes to the same data. Retain the serialized request body until the snapshot is terminal so a timeout can be retried byte for byte. For staged delivery, retry start with the same expected count. GetBill stores a server-computed SHA-256 for each accepted chunk. Retrying the same index with the same bytes returns 200; different bytes return chunk_content_conflict. Skipped indexes return chunk_out_of_order. Do not switch between one-request and staged delivery for the same snapshot_reference; this returns snapshot_delivery_mode_conflict.

Asynchronous states and recovery

core_applied: true means the atomic debt upsert and missing-debt reconciliation committed. A processing_error is therefore not a rollback signal. Successful completion exposes:
The status API exposes only safe failure metadata: reason and, when applicable, the one-based row and field. counts.resolved is the number of debts treated as settled because they were absent from the snapshot.

Costly phone destinations

A GetBill administrator configures this choice once per API- or bridge-managed campaign. It is disabled by default; the partner has no request option. Campaigns that share a timeline keep independent choices. A costly phone destination does not fail a valid row or prevent it from taking part in full_sync reconciliation. When the campaign has not allowed costly destinations, GetBill retains the debt and phone, continues eligible email and postal reminders, and blocks SMS, RCS, calls, WhatsApp, and voicemail for that phone. The same rule applies to secondary-contact phones. 202 Accepted only confirms receipt. After asynchronous processing, completed snapshot status exposes warnings in warnings, their total in warning_count, and the number excluded after the first 100 in warnings_omitted. Each warning includes its one-based row_number, code, message, field, and blocked_channels.

Three-day A/B/C resynchronization

Assume the source sends one complete snapshot per day: Use unique references such as export-2026-07-17-a1b2c3d4, export-2026-07-18-b2c3d4e5, and export-2026-07-19-c3d4e5f6. Never reuse day B’s reference to send day C’s data.

Daily cadence, rate limits, and transport recovery

Submit one complete snapshot per campaign each day. Only an exceptional second snapshot for the same campaign must wait until the prior snapshot reaches completed or failed. A processing_error instead blocks the campaign and requires operator or GetBill support recovery before another snapshot. Campaign limits are enforced per authenticated GetBill company:
  • reads and status: 1,000 requests/hour
  • provisioning, staged start/chunk/finalize/fail: 500 requests/hour
  • one-request snapshot submission: 50 requests/hour.
Every request body is limited to 10 MiB. A larger body returns 413 payload_too_large. On 429, wait for the number of seconds in the Retry-After response header before retrying. On an HTTP timeout after a mutation, retry idempotently as described above, then use the returned Location or known reference-based status URL. See Rate Limits and Error Handling.