Feedback

Feedback

Tell BillerAPI when a resource it produced is right or wrong. You report on the resource itself — a bill or an account connection — not on the internal run that produced it. The gateway attributes the feedback to the producing agent run and folds it into the self-improvement loop, so extraction quality improves for that biller over time.

Related guide: Submitting Feedback · Error catalog: Feedback errors

Soft-accept by design. Feedback is always recorded. When the producing run is unknown or has aged out, the response is still202 withattributable: false — you never get a hard error just because the run can’t be located. A404 means the resource doesn’t exist or isn’t yours.

The Feedback object

Response attributes

FieldTypeDescription
resource_type*stringEchoes the submitted resource_type.
resource_id*stringEchoes the submitted resource_id.
agent_type*stringThe agent whose output the feedback was attributed to (e.g. `recording_agent`, `script_execution_agent`).
signal*stringEchoes the submitted signal.
attributable*booleanTrue when the feedback was attributed to a known agent run (a producing run was found). False when the producing run is unknown or has aged out — the feedback is still recorded as observed and returned with 202 (soft-accept).
run_idstringThe agent run the feedback was attributed to. Omitted when `attributable` is false.
already_existed*booleanTrue when this exact submission was already recorded (idempotent replay). False when this submission wrote a new record.
Example Feedback response
JSON
{
  "resource_type": "bill",
  "resource_id": "bill_abc123",
  "agent_type": "recording_agent",
  "signal": "wrong_amount",
  "attributable": true,
  "run_id": "run_abc123",
  "already_existed": false
}
POST/v1/feedback

Submit feedback about a resource. Authenticate with yourAPI key /API key. Idempotent: send the same idempotency_key with an identical body to retry safely.

Request body (application/json)

FieldTypeDescription
resource_type*string (enum)The kind of resource the feedback is about: `bill` or `account_connection`. (`payment` is reserved — see below.)
resource_id*stringThe id of the resource — a bill id or an account-connection (account link) id. Ownership is enforced tenant-scoped against your client. Max 256 chars.
signal*string (enum)What you observed. Valid values depend on `resource_type` — see the Signal vocabulary section. Max 64 chars.
idempotency_key*stringRequired so retries do not double-count. Recommended format: ULID or `idem_<timestamp>_<resource_id>`. The `Idempotency-Key` header is an optional override; this body field is authoritative. Max 256 chars.
notesstringFree-text notes. PII-safe storage required; never echoed back in metrics. Max 4096 chars.

Returns: The feedback object on 202 Accepted.attributable is false when the producing run could not be located (still recorded). On idempotent replay, already_existed is true.

curl -X POST "https://sandbox.api.billerapi.com/v1/feedback" \
  -H "Authorization: Bearer $BILLERAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "resource_type": "bill",
    "resource_id": "bill_abc123",
    "signal": "wrong_amount",
    "idempotency_key": "idem_2026-06-25T18:00:00Z_bill_abc123",
    "notes": "Bill shows $0 but my paper bill says $84.32."
  }'

Signal vocabulary

The valid signal values depend on resource_type. Each type has one positive signal (“this is correct”) plus the ways it can be wrong. A signal that isn’t valid for the resource returns 400 FEEDBACK_INVALID_SIGNAL.

resource_type: "bill"

Bill signals

FieldTypeDescription
bill_correctpositiveThe bill is accurate — confirms the extraction was right.
wrong_amountincorrectThe amount due is wrong.
wrong_due_dateincorrectThe due date is wrong.
wrong_statusincorrectThe paid/unpaid status is wrong (e.g. shows due but already paid).
duplicate_billincorrectThis bill is a duplicate of another.
not_my_billincorrectThis bill does not belong to the account.
missing_line_itemsincorrectCharges / line items are missing.
stale_dataincorrectThe data is out of date.

resource_type: "account_connection"

Account-connection signals

FieldTypeDescription
accounts_correctpositiveThe discovered accounts are correct.
wrong_accountincorrectA discovered account is wrong.
missing_accountincorrectAn account that should have been discovered is missing.
wrong_biller_matchedincorrectThe connection was matched to the wrong biller.
duplicate_accountincorrectA discovered account is a duplicate.

resource_type: "payment" is reserved. Submitting it returns 501 PAYMENT_EXECUTION_NOT_AVAILABLE.

Status codes

Responses

FieldTypeDescription
202 AcceptedsuccessFeedback recorded. `attributable` is true when a producing run was found, false on soft-accept (run unknown / aged out).
400 FEEDBACK_INVALID_SIGNALerrorThe signal is not valid for the resource_type, or `idempotency_key` is missing.
401errorMissing or invalid client credentials.
404 FEEDBACK_RUN_NOT_FOUNDerrorThe resource does not exist or is not owned by your client (collapsed — no cross-tenant existence oracle).
409 FEEDBACK_ALREADY_SUBMITTEDerrorFeedback for this resource was already submitted under a different idempotency_key. Reuse the original key for an idempotent replay.
501 PAYMENT_EXECUTION_NOT_AVAILABLEerrorReturned for `resource_type: "payment"` — payment feedback is reserved and not yet available.

Idempotency semantics

This endpoint follows the standard BillerAPI idempotency contract. The idempotency_key is required (not just recommended) so retries don’t double-count.

  • Replay — same idempotency_key + identical body: returns the original payload with already_existed: true. Safe to retry on network failure.
  • Already submitted (different key, same resource) — a different key for the same resource returns 409 FEEDBACK_ALREADY_SUBMITTED. Reuse the original key to replay.
Was this page helpful?