API reference

Every procedure an API key may call, with its request fields and an example answer. The guide, The Chargeless API: your backend, explains the basics (keys, errors, retries, limits) and walks through the flows; this page is the list. The fields here come from openapi/backend-api/v1.yaml, which is generated from the protos and holds every field with its description. Where this page and that file differ, the file wins.

These 20 are all there is for an API key. Any other procedure answers permission_denied.

How to read this page

Every procedure is a POST of a JSON body to https://api.chargeless.io/{service}/{procedure}, with your key and Content-Type: application/json. The examples show only the body:

sh
curl -sS https://api.chargeless.io/sr.cases.v1.CasesService/ListActions \
  -H "Authorization: Bearer $CHARGELESS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"pageSize": 50}'
  • Field names are lowerCamelCase, enums are their names as strings, 64-bit integers (amountMinor, number, counts) are strings in answers, times are RFC 3339 in UTC. A field at its default (empty, zero, false) is left out of an answer, so read a missing field as its default.
  • Money is {"amountMinor": "1999", "currency": "USD"}: an integer in the currency's minor unit and an ISO 4217 code. Totals are per currency, never summed across currencies.
  • Ids are opaque strings. The ledger's ids (a customer, a transaction, a subscription, an action, a case) are what the API returns and takes back; a provider's id (ch_…, sub_…, cus_…) is returned beside them and accepted only where a field says so.
  • A few request fields exist only for Chargeless's own chat, help site and ticket automation (transcript, ticketId, answeredMessageId, sessionId on a ticket, address, portalBindingId, includeRetention). A request from an API key that sets one of them is refused with invalid_argument. They are left out below.
  • Some answer fields are sent to the panel's members only and are always empty for an API key: a customer's email (customerEmail, maskedCustomerEmail, SubscriptionCustomer.email), a provider dashboard link, a case's notes and customer statistics, and the plan list of ListSubscriptions.

Pages

The lists page with pageSize and pageToken: send nextPageToken back as pageToken unchanged, with the same filters, until it comes back empty. A token is opaque and works only with the filters it was made for.

Procedure pageSize Time range
ListActions, ListCases, ListProviderCalls 1–200, default 50 from, to optional (not on ListCases)
ListRefunds, ListDisputes, ListFraudWarnings, ListSubscriptions 1–100, default 50 from and to required, at most 400 days apart
ListVersions at most 100 a page pages with beforeVersion and hasMore instead
Lookup limit: default 20, at most 100 charges none

from is inclusive and to exclusive. Lists are newest first.

Identity

Prove who a customer is before you read their charges or act for them. Chargeless binds a proof to a set of customer rows, at most one account customer and one guest customer per payment connection (a guest is the payer of guest payments, known by the checkout email): pass the whole set on.

Verify

sr.identity.v1.IdentityService/Verify checks an identity token your server signed (HS256 with the Widget Signing Secret; the claims are in the guide) and returns the customer it binds.

Field Type Meaning
token string The signed token. Required
provider string Optional: stripe or merchant. Empty means the kind of the connection the token resolves in
json
{"token": "eyJhbGciOiJIUzI1NiIs…"}
json
{
  "customerId": "01a1aff4-5117-79a0-a966-68ed1a264ea1",
  "providerCustomerId": "cus_Q8x…",
  "method": "IDENTITY_METHOD_SIGNED_TOKEN",
  "connectionId": "01a1aff4-50ab-74ce-9c05-b142b747606c",
  "verifiedAt": "2026-11-06T09:30:00Z",
  "expiresAt": "2026-11-06T09:45:00Z"
}

customerId is the ledger customer: pass it as identity.customerId on Submit and in customerIds on Lookup. A token that does not verify or has expired is unauthenticated; a customer the ledger does not hold yet is not_found.

LookupCustomer

sr.identity.v1.IdentityService/LookupCustomer finds the customers an email address belongs to: in each live payment connection, the one customer with that address on file. An address that several customers share in one connection binds nobody there.

Field Type Meaning
email string Matched case-insensitively
provider string Optional: stripe or merchant to look in connections of that kind only
json
{"email": "[email protected]"}
json
{
  "found": true,
  "customerId": "01a1aff4-5117-79a0-a966-68ed1a264ea1",
  "providerCustomerId": "cus_Q8x…",
  "customers": [
    {
      "customerId": "01a1aff4-5117-79a0-a966-68ed1a264ea1",
      "providerCustomerId": "cus_Q8x…",
      "connectionId": "01a1aff4-50ab-74ce-9c05-b142b747606c"
    }
  ]
}

A lookup is not a proof by itself: it says who an address belongs to in your records. Use it for an address your own system has verified (a signed-in customer, a confirmed address), never for an address someone typed into a form; for those, send the request through SubmitCustomerRequest with email, and the address's owner proves it.

Transactions

Lookup

sr.transactions.v1.TransactionsService/Lookup lists a verified customer's recent charges, newest first, and their subscriptions, across their payment connections, each charge with what remains refundable. A merchant-hosted payment system is read first; when it cannot be read, the answer is unavailable and nothing stale is returned.

Field Type Meaning
customerIds string[] The verified set: ledger customer ids, at most one account and one guest customer per connection and at most 10
customerId string One customer; with customerIds empty, the set of this one
limit integer Charges to return across the set: default 20, at most 100
json
{"customerIds": ["01a1aff4-5117-79a0-a966-68ed1a264ea1"], "limit": 20}
json
{
  "transactions": [
    {
      "id": "01a1aff4-53d6-7334-8e2d-9d3d35bfcff5",
      "publicRef": "PAY-7K3F9QS",
      "provider": "stripe",
      "providerTransactionId": "ch_3Q8x…",
      "amount": {"amountMinor": "1900", "currency": "EUR"},
      "refundableRemainder": {"amountMinor": "1900", "currency": "EUR"},
      "state": "succeeded",
      "occurredAt": "2026-11-02T14:05:11Z",
      "cardBrand": "visa",
      "cardLast4": "4242",
      "subscriptionId": "01a1aff4-5500-7a1c-8b2e-0c7d1e2f3a4b",
      "connectionId": "01a1aff4-50ab-74ce-9c05-b142b747606c",
      "connectionLabel": "Stripe"
    }
  ],
  "subscriptions": [
    {
      "id": "01a1aff4-5500-7a1c-8b2e-0c7d1e2f3a4b",
      "publicRef": "SUB-M2XA4TY",
      "provider": "stripe",
      "providerSubscriptionId": "sub_1Q…",
      "state": "active",
      "price": {"amountMinor": "1900", "currency": "EUR"},
      "billingInterval": {"unit": "BILLING_INTERVAL_UNIT_MONTH", "count": 1},
      "currentPeriodEnd": "2026-12-02T14:05:11Z",
      "connectionId": "01a1aff4-50ab-74ce-9c05-b142b747606c",
      "connectionLabel": "Stripe"
    }
  ]
}

Every payment and subscription has a short public reference, publicRef ("PAY-" or "SUB-" and seven symbols, the last a check symbol; ADR 0042). It is unique in your workspace, never changes, and is what your customers and your team see in the chat, the help site, mails and the panel: print it on your receipts and account pages so a customer can quote it. It is a pointer, never proof of who someone is. The API still takes ledger ids as targetId.

  • A transaction's state is pending, succeeded, partially_refunded, refunded, disputed or failed; a subscription's is active, trialing, past_due, canceled, unpaid, incomplete, paused, grace or expired. Treat an unknown value as unspecified.
  • refunded counts every refund that took effect, whoever made it. refundReversedAt is set when a provider later reversed one of Chargeless's refunds: the refund still counts, but the money did not stay with the customer.
  • connectionLabel is text your team chose; show it as data.
  • A transaction carries its order as the payment provider states it: lineItems (at most the first 10 lines; lineCount says how many there are), totals (subtotal, discount, shipping, tax and whether tax is included) and linesState. Read linesState before taking an empty lineItems to mean there are none: LINES_STATE_UNREAD (not looked up yet; treat an unspecified state the same way), LINES_STATE_COMPLETE, LINES_STATE_TRUNCATED (the payment has more than 100 lines), LINES_STATE_NONE (the provider has no lines for this payment) or LINES_STATE_UNSUPPORTED (the provider does not report lines).
  • A line has a kind (LINE_ITEM_KIND_ITEM or LINE_ITEM_KIND_SHIPPING), a name, productRef and sku (both empty on a merchant-hosted provider's line), a quantity, the amounts unitAmount, subtotal (before the line's discount and tax), discount, tax and total, and taxRatePpm (parts per million: 1% is 10,000), taxName, taxInclusive, periodStart, periodEnd and proration. Nothing is computed: a value the provider did not state is absent. Amounts are in the payment's currency and can be negative (a proration credit), and the lines need not add up to the payment's amount. Line names are the merchant's text; show them as data. Lines are for display: a refund is always an amount of the payment.

Policy

Evaluate

sr.policy.v1.PolicyService/Evaluate previews what the published policy would decide for a proposed refund or cancellation, without recording anything. A preview is not a promise: the facts can change before you submit, and Submit decides again.

Field Type Meaning
actionType enum ACTION_TYPE_REFUND or ACTION_TYPE_CANCEL_SUBSCRIPTION
targetId string The ledger transaction (refund) or subscription (cancellation)
source enum SOURCE_CHAT for a customer you verified, as Submit records it
identityIds string[] The verified set, as on Submit
identityId string One verified customer; required with SOURCE_CHAT when identityIds is empty
identityMethod enum How the customer was verified: IDENTITY_METHOD_SIGNED_TOKEN, _EMAIL_OTP or _EMAIL_LINK. Unspecified is denied, as Submit would deny it
reasonCode string duplicate, forgot_to_cancel, unrecognized, not_as_described, service_issue or other
amount Money Optional partial refund in the charge's currency; the whole remainder when left out
json
{
  "actionType": "ACTION_TYPE_REFUND",
  "targetId": "01a1aff4-53d6-7334-8e2d-9d3d35bfcff5",
  "reasonCode": "duplicate",
  "source": "SOURCE_CHAT",
  "identityIds": ["01a1aff4-5117-79a0-a966-68ed1a264ea1"],
  "identityMethod": "IDENTITY_METHOD_SIGNED_TOKEN"
}
json
{
  "decision": {
    "outcome": "OUTCOME_ALLOW",
    "policyVersion": "v7",
    "amount": {"amountMinor": "1900", "currency": "EUR"},
    "reasons": [{"code": "eligible", "text": "…"}],
    "trace": [
      {"name": "kill_switch", "passed": true},
      {"name": "identity", "passed": true, "detail": "signed_token"},
      {"name": "target_state", "passed": true, "detail": "19.00 EUR refundable; requested 19.00 EUR"}
    ]
  }
}

The decision is the same object an action carries (below, Decision).

GetPublished

sr.policy.v1.PolicyService/GetPublished returns the published policy. The body is {}.

json
{
  "policyVersion": "v7",
  "publishedAt": "2026-11-01T08:00:00Z",
  "document": "eyJ2ZXJzaW9uIjoxLCJpZGVudGl0eSI6…"
}

document is the canonical policy JSON as bytes, so it arrives base64-encoded: decode it to read the policy (policy/v1 in the contracts). A workspace with no published policy answers failed_precondition.

ListVersions

sr.policy.v1.PolicyService/ListVersions lists every stored version, newest first, at most 100 a page. Versions are never changed or removed.

Field Type Meaning
beforeVersion integer Only versions older than this number; 0 or left out starts from the newest
json
{
  "versions": [
    {
      "policyVersion": "v7",
      "number": 7,
      "published": true,
      "publishedAt": "2026-11-01T08:00:00Z",
      "documentSha256": "e83c1abc4fac148b23fadf553c571b1ce87fa8d84de80fbd5de0c1b935d55464",
      "note": "Lower the auto-refund cap for TRY"
    }
  ],
  "hasMore": true
}

With hasMore, ask again with beforeVersion set to the last number. A superseded version carries supersededAt; one that restored an earlier version carries restoredFromVersion.

GetVersion

sr.policy.v1.PolicyService/GetVersion returns one version and its document (base64, as above).

json
{"policyVersion": "v6"}

The answer is {"version": {…as in ListVersions…}, "document": "…"}; a version the workspace does not have is not_found.

Actions

Submit

sr.actions.v1.ActionsService/Submit decides an action with the published policy, records it and starts its execution at the payment provider. The flow around it is in the guide.

Field Type Meaning
idempotencyKey string Your key for the intent, reused on every retry: backend:{your request id}:{action}:{target}. Required
type enum ACTION_TYPE_REFUND, ACTION_TYPE_CANCEL_SUBSCRIPTION or ACTION_TYPE_HANDOFF
targetId string The ledger transaction (refund) or subscription (cancellation). Required for both; left out for a handoff
identity object customerIds (the verified set), customerId and method, as Verify or LookupCustomer returned them
reasonCode string As for Evaluate
amount Money Optional partial refund; the whole refundable remainder when left out
requestedBy string Your label for where the request came from, shown on the action. Required
handoffReason string Required with ACTION_TYPE_HANDOFF: a code of [a-z0-9_], at most 64 characters. Anything else is recorded as unspecified, and the handoff still happens
waitSeconds integer How long to wait for the provider's outcome before answering: default 5, at most 10
locale string Optional BCP 47 language (en, tr, pt-BR): the language of a ticket a handoff opens
json
{
  "idempotencyKey": "backend:ord_8812:refund:01a1aff4-53d6-7334-8e2d-9d3d35bfcff5",
  "type": "ACTION_TYPE_REFUND",
  "targetId": "01a1aff4-53d6-7334-8e2d-9d3d35bfcff5",
  "reasonCode": "duplicate",
  "identity": {
    "customerIds": ["01a1aff4-5117-79a0-a966-68ed1a264ea1"],
    "method": "IDENTITY_METHOD_SIGNED_TOKEN"
  },
  "requestedBy": "account-page",
  "waitSeconds": 5
}
json
{
  "action": {
    "id": "01a1aff5-427d-765f-a005-d2675fe290ab",
    "caseId": "01a1aff5-427b-7a35-b2a4-1f8e6d0c9b11",
    "type": "ACTION_TYPE_REFUND",
    "status": "ACTION_STATUS_EXECUTED",
    "targetId": "01a1aff4-53d6-7334-8e2d-9d3d35bfcff5",
    "customerId": "01a1aff4-5117-79a0-a966-68ed1a264ea1",
    "amount": {"amountMinor": "1900", "currency": "EUR"},
    "reasonCode": "duplicate",
    "decision": {"outcome": "OUTCOME_ALLOW", "policyVersion": "v7", "reasons": [{"code": "eligible", "text": "…"}]},
    "policyVersion": "v7",
    "providerRef": "re_3Q…",
    "source": "SOURCE_CHAT",
    "requestedBy": "account-page",
    "createdAt": "2026-11-06T09:31:02Z",
    "executedAt": "2026-11-06T09:31:03Z"
  },
  "replayed": false
}

An action from an API key is recorded with source: SOURCE_CHAT, decided exactly as a chat in the widget. A handoff goes to your handoff destination: the team queue in the panel, the handoff.requested webhook, or both. A replayed key returns the first action with replayed: true; the same key with another type or target is failed_precondition. Dispute actions are Chargeless's own and are refused with invalid_argument.

When your policy refunds the last charge with a cancellation (subscriptions.refund_last_charge_if) and an allowed cancellation qualifies, the response also carries followup: that refund's own action, decided like any refund in the same transaction, with its own status (it can be denied or handed off while the cancellation goes through). Its key is the cancellation's key followed by :refund:{transaction_id} (44 characters more), so keep a cancellation's key under 160 characters: a longer one can make the refund's own key too long for the provider, and it then fails and goes to your team. Get on the cancellation returns it too, and Submit waits for it as it waits for the cancellation.

Get

sr.actions.v1.ActionsService/Get returns one action, as Submit answered it, with its current status.

json
{"actionId": "01a1aff5-427d-765f-a005-d2675fe290ab"}

The answer is {"action": {…}}.

Action

Field Meaning
status ACTION_STATUS_EXECUTED, _PENDING, _DENIED, _HANDOFF or _FAILED (each ACTION_STATUS_…). DENIED, HANDOFF, EXECUTED and FAILED are final. APPROVED is the short moment between the decision and the execution
type ACTION_TYPE_REFUND, _CANCEL_SUBSCRIPTION, _HANDOFF, _DISPUTE_ACCEPT or _DISPUTE_SUBMIT_EVIDENCE
source Who asked: SOURCE_CHAT (the widget and API keys), SOURCE_TICKET, SOURCE_PORTAL, SOURCE_FRAUD_ALERT, SOURCE_DISPUTE or SOURCE_MERCHANT_USER (your team, with actorUserId)
decision The decision behind the status (below)
amount The amount decided on; for a refund, what was or will be refunded
providerRef The provider's id for the refund or cancellation, once it has one
failure Set with FAILED: how the provider refused at execution
billedBy Paddle or FastSpring when that merchant of record billed the charge and confirms the refund itself
refundReversedAt Set when the provider reversed the refund after it succeeded; the action stays EXECUTED
manualOverride True when a member of your team allowed the action beyond policy
caseId, customerId, targetId, reasonCode, requestedBy, policyVersion, createdAt, executedAt As named

Decision

Field Meaning
outcome OUTCOME_ALLOW, OUTCOME_DENY or OUTCOME_HANDOFF
reasons Ordered {code, text, ruleId}: a stable machine code (outside_window, over_max_amount, rule_matched, …), English text for people, and ruleId when one of your rules decided. The set of codes is open: show an unknown code with its text
policyVersion The version that decided, "v<n>"
amount The refund amount, in the charge's currency
settlementAmount The same amount in your settlement currency, when the limits were compared in it
limitsApplied {name, limit, value, headroom} for each limit the decision measured
trace Each step of the fixed evaluation order: {name, passed, detail}
followups Suggested next actions, such as refunding the last charge after a cancellation

Requests from your form

SubmitCustomerRequest

sr.tickets.v1.RequestIntakeService/SubmitCustomerRequest takes one request from your own support form, opens a ticket and has the policy decide it. The flow is in the guide.

Field Type Meaning
requestId string Your id for the request, 1–128 characters of [A-Za-z0-9_-]. The idempotency key
action enum ACTION_TYPE_REFUND or ACTION_TYPE_CANCEL_SUBSCRIPTION
targetId string A ledger id, or your provider's id for the charge or subscription
connectionId string The payment connection of a provider id; empty: your first connection
identityToken or email string Exactly one proof: the signed identity token, or the address the form collected (which proves nothing until its owner confirms it)
reasonCode string As for Evaluate; empty reads as other
amount Money Optional partial refund
message string What the customer wrote, at most 4,000 characters
requesterName string The name the customer typed, at most 100 characters; never identity
locale string The form's language: the ticket's, its page's and its mail's
json
{
  "ticketId": "01a1b00b-2c4e-7f10-9a8b-6d5e4c3b2a19",
  "ticketNumber": "1042",
  "pageUrl": "https://acme.help.chargeless.io/t/9fK2…",
  "outcome": "CUSTOMER_REQUEST_OUTCOME_IDENTITY_REQUIRED",
  "reasonCode": "identity_required",
  "actionId": "01a1b00b-2c51-7d0e-8f3a-5b4c3d2e1f00",
  "replayed": false
}

outcome is CUSTOMER_REQUEST_OUTCOME_EXECUTED, _PENDING, _DENIED, _HANDOFF or _IDENTITY_REQUIRED. Errors beyond invalid_argument are failed_precondition with a detail naming the reason: TARGET_NOT_FOUND, INVALID_IDENTITY_TOKEN, NO_REPLY_ADDRESS (the token's customer has no address on file), TENANT_NOT_LIVE, or KEY_REUSED (the same requestId with other content).

Workspace

GetTenant

sr.tenant.v1.TenantService/GetTenant returns your workspace. The body is {}. It is the one call that still answers while Chargeless has suspended the workspace.

json
{
  "tenant": {
    "id": "01a1b700-5c8b-78d0-9ac5-0e50fde96cc5",
    "slug": "acme",
    "name": "Acme Store",
    "status": "TENANT_STATUS_ACTIVE",
    "settlementCurrency": "USD",
    "timeZone": "Europe/Istanbul",
    "activatedAt": "2026-11-07T17:13:36.978820Z",
    "handoffDestination": "HANDOFF_DESTINATION_TEAM_QUEUE_AND_WEBHOOK",
    "widgetOrigins": ["https://shop.acme.example"]
  },
  "helpSite": {"slug": "acme", "url": "https://acme.help.chargeless.io", "chosen": true},
  "customerPortal": {"enabled": true, "url": "https://acme.help.chargeless.io", "codeSignIn": true}
}
  • status is TENANT_STATUS_ONBOARDING (not live yet: onboarding lists what is left), TENANT_STATUS_ACTIVE or TENANT_STATUS_SUSPENDED.
  • killSwitch (your emergency stop), operatorHold (Chargeless's) and circuitBreakerOpen are left out while false. While any of them is true, no automatic refund or cancellation runs.
  • test is true for a test workspace.
  • The answer also carries the assistant's tone (assistantStyle), your help links and the help site's branding. tenant.paymentProvider and tenant.handoff are deprecated: a workspace has several payment connections and webhook endpoints.

Actions, cases and payments

sr.cases.v1.CasesService: what happened in your workspace, for your own reporting and reconciliation. Each of these is read-only.

ListActions

Every action, newest first.

Field Type Meaning
from, to time Optional bounds on createdAt
types enum[] Any of these action types
statuses enum[] Any of these statuses
sources string[] Any of chat, fraud_alert, dispute, system, ticket, merchant_user
pageSize, pageToken 1–200, default 50
json
{"from": "2026-11-01T00:00:00Z", "statuses": ["ACTION_STATUS_HANDOFF"], "pageSize": 50}

The answer is {"actions": [Action…], "nextPageToken": "…"}.

ListCases

The cases (a chat, a ticket, a fraud warning, a dispute, a staff action, a portal request), newest first, each with its latest decision and amount.

Field Type Meaning
types enum[] CASE_TYPE_CHAT_REFUND, _CHAT_CANCELLATION, _FRAUD_ALERT, _DISPUTE, _TICKET, _STAFF_ACTION, _PORTAL_REFUND, _PORTAL_CANCELLATION
statuses enum[] CASE_STATUS_OPEN, _RESOLVED, _HANDED_OFF, _FAILED
connectionIds string[] At most 10 payment connections; empty means all
pageSize, pageToken 1–200, default 50
json
{
  "cases": [
    {
      "id": "01a1b7d7-cf73-7d19-aead-31ccf144948c",
      "number": "348",
      "type": "CASE_TYPE_TICKET",
      "status": "CASE_STATUS_HANDED_OFF",
      "customerId": "01a1b700-5e57-7515-bc66-6bf4bec0d27d",
      "transactionId": "01a1b700-83f0-7f25-af58-82a8474e203d",
      "ticketId": "01a1b7d6-c2e2-785c-af0d-e6c7a0209674",
      "connectionId": "6e776da5-5c08-8dd5-aa9d-6c9736dfdbea",
      "connectionLabel": "Stripe",
      "openedAt": "2026-11-07T21:08:56.302765Z",
      "closedAt": "2026-11-07T21:08:56.302765Z",
      "summary": {
        "latestDecision": {
          "actionId": "01a1b7d7-cf75-7c0b-b3b9-a9013967a01a",
          "actionType": "ACTION_TYPE_REFUND",
          "actionStatus": "ACTION_STATUS_HANDOFF",
          "outcome": "OUTCOME_HANDOFF",
          "reasonCode": "reason_not_auto_refundable",
          "decidedAt": "2026-11-07T21:08:56.309789Z"
        },
        "amount": {"amountMinor": "1999", "currency": "USD"},
        "amountKind": "CASE_AMOUNT_KIND_REQUESTED"
      }
    }
  ],
  "nextPageToken": "MTc5NDA4NTcz…"
}

number is what people quote ("CS-348"). A filter by connection is bounded in time; past it the answer is deadline_exceeded (narrow the filter, or retry).

GetCase

One case with its timeline, its actions and the facts each decision was evaluated on.

json
{"caseId": "01a1b7d7-cf73-7d19-aead-31ccf144948c"}
Answer field Meaning
case The case, as in ListCases without summary
actions Its actions, as Action
actionFacts "What we saw, when": per action, the facts its decision used (the target, the customer's counters, the stops, the identity, and for a merchant-hosted system the reads it made). Re-evaluating them at the recorded policy version gives the recorded decision
timeline Append-only entries {id, at, kind, payload}: the decision, the execution, webhooks
charge The case's charge: provider reference, amount, card brand and last four
dispute, fraudWarning Set on a dispute or fraud-alert case

ListRefunds

Every refund on your charges, newest first: Chargeless's own (REFUND_ORIGIN_SUPPORTROUTE, with their action and case) and the ones made elsewhere, at the provider (REFUND_ORIGIN_PROVIDER) or in your own system (REFUND_ORIGIN_MERCHANT_SYSTEM).

Field Type Meaning
from, to time Required bounds on refundedAt, at most 400 days apart
origins enum[] Any of the three origins
states enum[] PAYMENT_REFUND_STATE_PENDING, _SUCCEEDED, _FAILED
connectionIds string[] At most 10
pageSize, pageToken 1–100, default 50
json
{
  "refunds": [
    {
      "id": "01a1b700-69cc-7080-b5ca-e541a95862d7",
      "origin": "REFUND_ORIGIN_SUPPORTROUTE",
      "provider": "stripe",
      "providerRefundId": "re_c58FA64x0aOqOxLK0I9ZjlZb",
      "amount": {"amountMinor": "4200", "currency": "USD"},
      "state": "PAYMENT_REFUND_STATE_SUCCEEDED",
      "refundedAt": "2026-11-07T17:13:40.044033Z",
      "charge": {
        "transactionId": "01a1b700-5ea6-736f-99fe-80e460b95079",
        "providerRef": "ch_8w2pTukEA4IOftQJexOZbddA",
        "amount": {"amountMinor": "4200", "currency": "USD"},
        "cardBrand": "visa",
        "cardLast4": "9772",
        "customerId": "01a1b700-5ea6-707e-bb61-b0763860a280",
        "customerProviderRef": "cus_aQYDQuFGnAjZ6rt25BbC8jvo"
      },
      "actionId": "01a1b700-65e6-7b4d-ae33-d46bf87e283f",
      "caseId": "01a1b700-65e6-76d0-9a8b-1325c5b3c1f2",
      "caseNumber": "5",
      "actionStatus": "ACTION_STATUS_EXECUTED",
      "source": "SOURCE_FRAUD_ALERT",
      "decisionReason": "eligible",
      "connectionId": "6e776da5-5c08-8dd5-aa9d-6c9736dfdbea",
      "connectionLabel": "Stripe"
    }
  ],
  "totals": [
    {"amount": {"amountMinor": "219885", "currency": "EUR"}, "refunds": "36"},
    {"amount": {"amountMinor": "790509", "currency": "USD"}, "refunds": "160"}
  ],
  "nextPageToken": "MTc5NDA3MTYy…"
}

totals is what the range refunded per currency (succeeded and not reversed, with the origin and connection filters), the same on every page. reversedAt marks a refund that was returned later.

ListDisputes

Disputes and inquiries, newest first, with their charge and what Chargeless did about each.

Field Type Meaning
from, to time Required bounds on openedAt, at most 400 days apart
statuses enum[] DISPUTE_STATUS_NEEDS_RESPONSE, _UNDER_REVIEW, _WON, _LOST, _WARNING, _CLOSED
reasons string[] The provider's reason codes, compared exactly (fraudulent), at most 20
connectionIds string[] At most 10
pageSize, pageToken 1–100, default 50

Each entry carries dispute (provider, id, status, amount, reason, evidenceDueBy, openedAt, closedAt, fundsWithdrawn), charge, the case, the latest action on it (actionType: accept, submit evidence or a handoff, and actionStatus), evidenceState and handledByProvider, which is true when a merchant of record (Paddle, FastSpring) runs the dispute itself.

ListFraudWarnings

Early fraud warnings, newest first, with their charge and the refund decision the fraud-alert workflow made for each (actionId is empty while it runs).

Field Type Meaning
from, to time Required bounds on warnedAt, at most 400 days apart
connectionIds string[] At most 10
pageSize, pageToken 1–100, default 50

Each entry carries provider, providerWarningId, fraudType, warnedAt, actionable (the charge could still be acted on), charge, the case and the decision (actionStatus, decisionReason), fromHistory (read from the provider's history and never handled) and handledByProvider.

ListSubscriptions

Subscriptions across your payment connections, newest first by the chosen time.

Field Type Meaning
rangeField enum SUBSCRIPTION_RANGE_FIELD_STARTED_AT or _CANCELED_AT. Required
from, to time Required bounds on that time, at most 400 days apart
states enum[] SUBSCRIPTION_STATE_ACTIVE, _TRIALING, _PAST_DUE, _CANCELED, _UNPAID, _INCOMPLETE, _PAUSED, _GRACE, _EXPIRED
customer string The provider's customer reference (cus_…, your customer_ref). The email form is for the panel only and answers permission_denied to an API key
planRef string The provider's plan or price reference, exactly
currency string The price's ISO 4217 currency
billingInterval object {unit, count}: only subscriptions renewing at exactly this interval
connectionIds string[] At most 10
pageSize, pageToken 1–100, default 50
json
{
  "subscriptions": [
    {
      "id": "01a1b700-732b-73e9-bdff-36fe4600be3c",
      "provider": "stripe",
      "providerSubscriptionId": "sub_zRD1wEx9r98zQYWAjTRFPDf2",
      "state": "SUBSCRIPTION_STATE_ACTIVE",
      "customer": {"id": "01a1b700-661c-74aa-a45d-8db455c36d2b", "providerRef": "cus_xXbSfStFNII7WdETMI6oe0l6"},
      "planRef": "price_kGmpyErZM0VmStFVzlC6gTqs",
      "price": {"amountMinor": "1500", "currency": "USD"},
      "billingInterval": {"unit": "BILLING_INTERVAL_UNIT_WEEK", "count": 1},
      "startedAt": "2026-11-06T17:13:35Z",
      "currentPeriodEnd": "2026-11-13T17:13:35Z",
      "cancelAtPeriodEnd": true,
      "canceledAt": "2026-11-07T17:13:35Z",
      "connectionId": "6e776da5-5c08-8dd5-aa9d-6c9736dfdbea",
      "connectionLabel": "Stripe"
    }
  ],
  "nextPageToken": "MTc5Mzk4NTIx…"
}

The plan's display name (planName, and the planName filter) is for the panel only.

ListProviderCalls

The calls Chargeless made to your own payment system (a merchant-hosted connection, see Connecting your own billing system), newest first, kept 90 days. No bodies and no personal data. A workspace without such a connection gets an empty page.

Field Type Meaning
from, to time Optional bounds on at
operations enum[] PROVIDER_OPERATION_DESCRIBE, _FIND_CUSTOMERS, _GET_CUSTOMER, _LIST_TRANSACTIONS, _GET_TRANSACTION, _GET_SUBSCRIPTION, _REFUND, _CANCEL_SUBSCRIPTION, _GET_OPERATION, _LIST_PAYMENT_ATTEMPTS
outcomes enum[] PROVIDER_CALL_OUTCOME_OK, _NOT_FOUND, _REFUSED, _INVALID_REQUEST, _CREDENTIALS_REJECTED, _IDEMPOTENCY_CONFLICT, _IN_PROGRESS, _RATE_LIMITED, _SERVER_ERROR, _TIMEOUT, _TRANSPORT_ERROR, _CONTRACT_VIOLATION
correlationId string Only the calls made for this action, case, ticket, session or check
connectionId string One connection; empty: all
pageSize, pageToken 1–200, default 50

Each call carries at, operation, outcome, outcomeDetail (a refusal code, or what the answer violated), httpStatus, latencyMs, attempt, requestId (the X-SR-Request-Id your logs have), correlationId and its kind, idempotencyKey for mutations, and errorRetryable with retryableMismatch when your error envelope's flag disagreed with its status.

GetProviderHealth

The health of a merchant-hosted connection, for your monitoring: the open provider alerts, the ones resolved in the last 7 days, and the last 24 hours of calls by outcome.

Field Type Meaning
connectionId string The merchant-hosted connection; empty: your first connection

The answer carries openAlerts and resolvedAlerts (kind: credentials rejected, contract violation, unavailable, credentials expiring; figures with up to three request ids), and supportPath, sync and check tallies by outcome over [windowStart, windowEnd). A Stripe connection gets {}. The answer may be up to 30 seconds old and is shared by every caller, so polling faster returns the same answer; resource_exhausted asks you to wait at least a second.