Skip to main content

Statement Descriptors

A statement descriptor is the short line of text a buyer sees next to a charge on their card statement or banking app. A clear descriptor is the single best way to cut "I don't recognize this charge" disputes — buyers who recognize the merchant don't call their bank.

A descriptor has two parts, and they behave very differently:

PartWhat it isWho controls itReliable?
Brand prefixYour business name — the part a buyer reads as "who charged me".Your merchant account, registered with your payment processor at boarding.Set once, at the account level — not per charge.
Dynamic tailA short per-transaction identifier appended after the brand (e.g. an order number).You, per charge, through the Payments API.Yes — this is the reliable lever.

Put together, a statement typically reads like:

BRAND*ORD-1234

where BRAND is your registered business name and ORD-1234 is the dynamic tail you sent on that specific charge.

The brand name is best-effort — the tail is the reliable lever

The brand prefix comes from the descriptor registered on your merchant account. On many processors the bank shows that registered name and ignores any business name sent on an individual charge — so treat the brand as account-level configuration, not an API field.

To change the brand a buyer sees, update the registered descriptor on your merchant account with your payment processor — not through this API. What you can reliably set per charge is the dynamic tail. Build for the tail; don't expect a per-charge name to override your account descriptor.

How the descriptor is configured

Descriptor behavior is configured per merchant, on the Von Payments side today (there is no self-serve dashboard control yet). Ask your Von Payments contact to set it up or change it. A configuration has two pieces:

  1. A fixed identity — your business name, plus optional city, country, phone, url, and postal code. These describe your business and, where a processor accepts a structured descriptor, travel with the charge.
  2. A dynamic-suffix rule — how the per-transaction tail is chosen. The rule has a source (where the tail comes from) and a fallback (what to do when that source is missing on a given charge).

Tail sources

The source decides which value becomes the tail. All except none read a field from the charge's metadata:

SourceReads fromTypical use
order_idmetadata.order_idShow the order number on the statement.
subscription_idmetadata.subscription_idShow the subscription a renewal belongs to.
customer_idmetadata.customer_idShow your internal customer reference.
custommetadata.<your key>Any metadata key you choose (e.g. product_name).
noneNo dynamic tail; the statement shows the brand only.

Fallbacks

The fallback decides what happens when the source field is absent or empty on a charge:

FallbackBehavior when the source field is missing
skipNo tail is added — the statement shows the brand alone.
pi_refThe last 8 characters of the payment intent ID are used as the tail, so the charge is still traceable.
literalA fixed text you configured is used as the tail.

Feeding the tail from your code

You supply the tail's value per charge in the PaymentIntent metadata — the same metadata object you already send on POST /v1/payment_intents. The key is fixed by your configured rule; you provide the value.

If your rule's source is order_id:

{
"amount": 4999,
"currency": "USD",
"metadata": { "order_id": "ORD-1234" }
}

If your rule uses a custom source with the key product_name:

{
"amount": 4999,
"currency": "USD",
"metadata": { "product_name": "Blue Widget" }
}

The buyer's statement then reads roughly BRAND*ORD-1234 or BRAND*Blue Widget (subject to the length and character rules below). If you omit the configured key on a charge, the rule's fallback applies.

The tail can never be sourced from buyer PII

A custom key that looks like buyer-identifying data — email, phone, card, ssn, tax_id, address, and similar — is rejected when the rule is set up. This is a deliberate guard: personal data must never end up printed on a bank statement. Choose a non-PII key such as order_id or product_name.

Length and character rules

Card networks give the whole descriptor very little room, so a few rules apply before anything reaches the bank:

  • Total length: 22 characters. The entire descriptor — brand prefix, the separator, and the tail — is capped at 22 characters. The prefix and separator consume part of that budget; the tail gets whatever remains.
  • The tail is hard-truncated. If the tail is longer than the remaining room, it is cut to fit — there is no ellipsis. A tail of ORDER-2026-000199 can land on the statement as ORDER-2026-00 if that's all that fits. Keep tails short and put the most identifying characters first.
  • Printable ASCII only. Tail values are reduced to printable ASCII (letters, digits, and common punctuation) before use; emoji, accented letters, and non-Latin characters are stripped out. The configured brand name is likewise limited to 22 printable-ASCII characters and can't contain < > \ ' " *.
Design the tail to survive truncation

Because the tail is cut, not summarized, front-load the part a buyer or your support team needs to recognize the charge. 1234-ORDER truncates more usefully than ORDER-NUMBER-1234.

Confirming what was sent

Every POST /v1/payment_intents response includes a resolved_descriptor object so your integration can confirm exactly what was applied — no dashboard or database access needed.

  • When a descriptor was applied, resolved_descriptor echoes what was dispatched, including the resolved dynamic suffix (the tail). Read it to see the exact tail that will reach the bank after truncation.
  • When nothing was applied, it's a skipped record naming the reason — for example, no descriptor is configured for your account. In that case the charge falls back to your processor's own default statement descriptor:
{
"resolved_descriptor": {
"kind": "skipped",
"reason": "no_config"
}
}

resolved_descriptor only ever reflects your own configured descriptor fields and the tail you sent — it never contains buyer data, so it's safe to log for reconciliation.