Skip to main content
POST

Authorizations

Authorization
string
header
required

Transaction-only beta key, issued with your beta access and always visible in the Transaction Enrichment Playground. Existing Logo.dev secret keys do not authenticate this beta.

Body

application/json

The body takes no fields other than these. An unrecognized field returns 400.

transaction
string
required

The merchant name or card descriptor. The API trims surrounding whitespace, then the value must be 1 to 1,024 characters.

Required string length: 1 - 1024
Example:

"Starbucks"

country_code
string

ISO 3166-1 alpha-2 country code, such as US or GB. Lowercase is accepted. The code is a hint for ambiguous names. It does not restrict results to that country. An unknown code returns 400. With transaction_context, the codes AQ, AX, TF, and VA return 400.

Required string length: 2
Example:

"US"

transaction_context
object

The real transaction values. Send them to identify the other party as a person or an organization, and to name the platform the purchase ran through. With context, the response adds entity_type.

When you send the object, date, amount, currency, and entry_type are required. The API fills in no placeholder values. Incomplete context returns 400 and does not count against the daily allowance.

The merchant string, the context, and the account holder details go to Logo.dev's enrichment provider. Each lookup carries its own context. The beta keeps no account history across lookups.

Response

A matched row or a cleaned row. Every non-empty transaction returns one. The examples are illustrative: they show the shape, not the result for a particular string.

domain
string | null
required

The merchant's domain. null on a cleaned row.

name
string
required

The display name. Present for every non-empty transaction.

  • When the Brand API resolves a brand for the domain, its name wins.
  • Otherwise it is the name the transaction lookup returned.
  • On a cleaned row it is the descriptor, tidied into a display name.

Descriptors arrive in one case, so a tidied name reads Fedex, not FedEx. When the Logo.dev brand corpus holds the same name, a cleaned row takes the company's own spelling. Only the name changes. The row stays cleaned at the same confidence.

Example:

"Starbucks"

entity_id
string | null
required

The merchant's Logo.dev brand id, the same id the Brand API uses. A brand keeps its id when its domain changes, so key your records on entity_id, not domain.

A row with an id has two sources that agree: the pipeline identified the merchant, and the Brand API resolves a brand for the same domain. Branch on entity_id, not on confidence.

null on a cleaned row, and on a matched row when the Brand API resolves no brand for the domain. A domain that Logo.dev has not indexed yet also returns null. A later lookup can return an id after the first crawl finishes.

Example:

"brand_5k2mq8h0000g00400000000017"

logo_url
string<uri> | null
required

The Logo CDN URL for the merchant's logo. null on a cleaned row. The URL has no token. Add your publishable key before you show it: https://img.logo.dev/starbucks.com?token=LOGO_DEV_PUBLISHABLE_KEY. The same applies to logo_url in parent and intermediary.

Example:

"https://img.logo.dev/starbucks.com"

parent
object | null
required

The company that owns the merchant, or null. It sits beside the merchant and never replaces it: a lookup for Facebook returns Facebook in domain, with Meta here.

Group totals on parent.entity_id to add up one company's brands. Facebook, Instagram, and WhatsApp become Meta. The owner's entity_id is the same id it has when it is the merchant, so the two join on one column.

parent is the nearest owner that Logo.dev records, not the top of the chain. Jaguar returns JLR, and JLR returns Tata Motors. To find the top, look up each parent in turn.

Coverage is thin. Logo.dev records a small, hand-verified list of ownership pairs, so most rows return null. A null means Logo.dev records no owner for this merchant. It does not mean the merchant is independent. parent is also null on a cleaned row, and when the Brand API resolves no brand for the owner's domain.

A rebrand onto a new domain can come back as a new identity. parent joins it to the old one only when both domains are in the ownership list.

intermediary
object | null
required

The platform the purchase ran through, or null. The merchant stays in domain. A coffee paid through Square returns the coffee shop, with Square here. The platform gets the same lookup as the merchant, keyed by its own domain, so you can group totals by platform on intermediary.entity_id.

intermediary is null in these cases:

  • The platform sold the item itself. A DashPass subscription is a purchase from DoorDash, so that row names DoorDash in domain.
  • The API identified no platform. This does not mean no platform was involved.

Without transaction_context, the API fills intermediary only when the enrichment provider answers the whole descriptor with a platform. The merchant checks then refuse the platform as the seller, and the API looks up the text after the prefix on its own. When the provider resolves the seller directly from a prefixed descriptor, intermediary stays null on a correct row. Send transaction_context when you need the platform named reliably.

A cleaned row can keep a platform. This happens when the checks reject the platform's domain and the text after the prefix identifies nobody.

status
enum<string>
required

matched when the API identified a merchant domain. cleaned when it did not. There is no not-found result: a cleaned row is an answer, with a tidied display name and null in domain, entity_id, logo_url, and parent.

A row is cleaned for one of two reasons:

  • Nothing identified the descriptor.
  • A candidate domain failed a merchant check. The checks catch repeated hostnames, directory and profile hosts, a known platform in the merchant's place, and known descriptor conflicts. They run on saved results and on new lookups.

A failed check drops the domain and uses the tidied descriptor as the name. A platform that a check removes from the merchant's place still comes back in intermediary. An organization with no usable website also comes back cleaned. The API never puts a payment processor's or parent company's domain in place of the merchant's.

Available options:
matched,
cleaned
match_type
enum<string>
required

The pipeline stage that produced the row, strongest first. The set is closed.

  • enriched_context: identified from the full transaction, with entry type and account holder.
  • descriptor_domain: the descriptor printed the merchant's own domain.
  • resolved_entity: identified from the descriptor alone, with no transaction context.
  • searched_name: the Logo.dev brand corpus recognized the cleaned name.
  • cleaned_descriptor: nothing identified the merchant. name holds the tidied descriptor.

descriptor_domain and searched_name are fallbacks. They run only when the enrichment provider identifies nobody. A descriptor that the provider recognizes never reaches them: CHEWY.COM XXX-XXX-7111 FL prints a domain and still returns resolved_entity. Both fallbacks face the same merchant checks, so a row that fails them comes back cleaned.

Read match_type from the row. Do not predict it from the descriptor, because the same string can take a different path as the provider's coverage changes.

Available options:
enriched_context,
descriptor_domain,
resolved_entity,
searched_name,
cleaned_descriptor
confidence
number
required

A score from 0 to 1. Two inputs set it: the match_type that produced the row, and whether the Brand API resolves a brand for the same domain. A printed domain scores above a name resolved from the descriptor, and a corpus search scores below it. A failed merchant check sends the row to the floor. A matched row with no brand has a lower score and a null entity_id.

The same input always gets the same score, so two runs of a batch compare cleanly.

Logo.dev publishes no cut-off, because the right line depends on what the row feeds. Use the score to rank and triage, for example to sort a review queue. To branch, read entity_id. Logo.dev can recalibrate the score without changing which rows have an id. A high score does not guarantee accuracy.

Required range: 0 <= x <= 1
entity_type
enum<string> | null

Present only when the request includes transaction_context. person or organization, as the enrichment provider classified the other party, or null when it classified nobody.

A null does not mean the API found no merchant. A later stage can identify one, so a matched row can carry null here. A person always comes back as a cleaned row.

Without context, the API does not detect people. It treats a personal name as a merchant name, so Jane Doe can match an organization with a similar name.

Available options:
person,
organization,
null