Get started enriching transactions with Spade
ⓘ Reading Time: 15 mins
This guide walks you through your first enrichment and shows you how to get the most out of Spade's card transaction enrichment API. We recommend working along as you go, using your API key for our sandbox environment.
If you need an API key, please contact us at [email protected] "Request Access" on our website.
Each API key is scoped to a specific environment, so you’ll have a separate API key for sandbox vs. production.
Spade's Approach
Before starting integration, it's important to understand Spade's approach to enrichment and key concepts for successful implementation.
Spade takes a unique approach to card transaction enrichment. We have built data partnerships with a variety of providers, including players in the payments value chain, first-party merchants, location data providers, state registry databases, and more. We combine these data sources – which on their own are much less powerful – into a proprietary merchant database hosted by Spade. This database is constantly reviewed, updated and quality checked. Instead of simply extracting information from or cleansing transaction strings, when we receive transaction data from you, we match it to a real merchant entity in our database - returning granular merchant information including clean name, custom category, geo-location, and more, all in <70ms.
Typically, with a proper implementation you'll see merchant match rates of ~95%. Even when we don't match on a merchant, we will still clean the merchant name, sort the data (e.g., move a phone number from the city to phone number field), and provide a category.
When we enrich transactions, we return information in two sections: transaction info and counterparty info.
- Transaction info: this is high level information about the transaction, including spending type, channel (e.g., physical or digital), and information on third parties.
- A third party is any entity besides the counterparty involved in a transaction, e.g., a payment processor, delivery service, or BNPL provider. We separate this infromation and tell you the third party type as well as providing detail on counterparty when available.
- Counterparty info: this is information on the entity you interact with directly when you make a purchase (in most cases a merchant), including a business name, logo, website, location, and more.
More detail on fields returned will be provided in the guide below.
Currently, Spade's API only enriches card transactions occuring at US-based merchants. If you are interested in other types of transaction enrichment (e.g., aggregator or bank data) or international products, email [email protected]@spade.com to receive launch updates.
Card Transaction Enrichment API
Performing your first enrichment
For the purposes of this guide, we'll be working with the following card transaction as an input:
{
// The time the transaction occurred (in ISO-8601 format)
"occurredAt": "2023-03-14T01:42:00Z",
// The "acquirerId" (also known as the "Network ID", "Card Acceptor ID", or "Merchant ID")
"acquirerId": "123456789",
// This is the "doing business as" merchant name
"merchantName": "SQ*WMSUPERCENTER#582",
// Your ID for this transaction (should not contain any PII)
"transactionId": "166c5ad8-8a94-4964-a659-03cdb64525f2",
// Your ID for this user (should not contain any PII)
"userId": "f841399e-d095-4e7f-b004-c39d7e3fa329",
// The spend category (typically the MCC, but some other codes are accepted)
"categoryCode": "5469",
"categoryType": "MCC",
// The transaction amount and currency
"amount": "42.00",
"currencyCode": "USD",
// The location information
"location": {
"city": "PORT ORANGE",
"region": "FL",
"country": "USA"
}
}
This transaction represents a card purchase that occurred at the Walmart Supercenter on 1590 Dunlawton Ave in Port Orange, Florida.
Unfortunately, with the limited information available on standard card transactions, we don't know any of this information at the moment. All we know is that $42 was spent at a place called SQ*WMSUPERCENTER#582
in Port Orange, Florida.
Spade's API will add clarity and context to this transaction. Let's ask Spade to enrich it.
import requests
raw_transaction = {
"occurredAt": "2023-03-14T01:42:00Z",
"acquirerId": "123456789",
"merchantName": "SQ*WMSUPERCENTER#582",
"transactionId": "166c5ad8-8a94-4964-a659-03cdb64525f2",
"userId": "f841399e-d095-4e7f-b004-c39d7e3fa329",
"categoryCode": "5469",
"categoryType": "MCC",
"amount": "42.00",
"currencyCode": "USD",
"location": {
"city": "PORT ORANGE",
"region": "FL",
"country": "USA"
}
}
response = requests.post("https://east.sandbox.spade.com/transactions/enrich", json=raw_transaction, headers={"X-Api-Key": "<Your API Key Here>"})
enriched_transaction = response.json()
print(enriched_transaction)
Sending the above request returns:
{
"transactionInfo": {
"type": "spending",
"thirdParties": [
{
"id": "8fbe0c0b-e54a-35a8-b8ff-0d982c84fc55",
"name": "Square",
"type": "payment_processor",
"logo": "https://static.v2.spadeapi.com/logos/8fbe0c0be54a35a8b8ff0d982c84fc55/light.png"
}
],
"spendingInfo": {
"channel": {
"value": "physical"
}
}
},
"counterparty": [
{
"id": "d730906b-f1a8-49f1-9939-f27390170a6d",
"name": "Walmart",
"legalName": "Walmart Inc",
"industry": [
{
"id": "011-000-000-000",
"name": "Retail",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
},
{
"id": "011-018-000-000",
"name": "General Goods",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
},
{
"id": "011-018-002-000",
"name": "Department Stores",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
}
],
"matchScore": 93.6,
"location": [
{
"id": "380e18b7-bf9e-3545-b27e-80e36301c540",
"address": "1590 Dunlawton Ave",
"city": "Port Orange",
"region": "FL",
"postalCode": "32127",
"country": "USA",
"phoneNumber": "+13867562711",
"latitude": 29.116576,
"longitude": -81.02062
}
],
"logo": "https://v1.spadeapi.com/logos/verified/walmart.png?size=large",
"medianSpendPerTransaction": 22.77,
"phoneNumber": "+18004386278",
"website": "walmart.com"
}
],
"enrichmentId": "78ba8476-fbe8-48cc-bbd0-1756a0eef0e3"
}
There's a lot here - let's take a look at the enriched transaction one piece at a time.
transactionInfo
transactionInfo
is an object containing high-level information about the transaction:
"transactionInfo": {
// The transaction type. In this case, the user is spending money.
"type": "spending",
// The list of third parties includes any entities besides the counterparty involved in a transaction (buy-now-pay-later providers, delivery services, marketplaces, payment processors, POS systems, etc...)
"thirdParties": [
{
"id": "8fbe0c0b-e54a-35a8-b8ff-0d982c84fc55",
"name": "Square",
"type": "payment_processor",
"logo": "https://static.v2.spadeapi.com/logos/8fbe0c0be54a35a8b8ff0d982c84fc55/light.png"
}
],
"spendingInfo": {
// The channel represents Spade's assessment of whether the transaction was at a digital or physical merchant
"channel": {
"value": "physical"
}
}
}
Make sure that you utilize the third parties list. Some third parties--especially food delivery services such as Uber Eats or Doordash--tend to remove identifying counterparty information from transactions, which makes it more difficult for Spade to identify the counterparty. When there is a third party match but no counterparty match, we recommend surfacing the third party name and logo to users.
counterparty
For a given transaction, the counterparty is the entity that you interact with directly when you make a purchase (in most cases, a merchant such as Walmart). In Spade's response object, counterparty
is a list of counterparties matched to the transaction, ordered by descending match score. Typically, this list will contain a single matched counterparty; however, if there are multiple potential matches and we aren't certain which one is the real counterparty, we may return multiple results.
Matching vs. Cleaning
Remember that Spade takes a ground truth approach to transaction enrichment. Thus, you'll notice that this counterparty is not simply a cleansed version of the data we received. Instead, it represents the actual counterparty and location involved in this transaction, pulled from our merchant database.
"counterparty": [
{
// This is a unique ID associated with this counterparty. We recommend building rules and/or mappings using this ID rather than the counterparty's name.
"id": "d730906b-f1a8-49f1-9939-f27390170a6d",
"name": "Walmart",
"legalName": "Walmart Inc",
// This counterparty's industry (in the context of the current transaction). The industry is a hierarchical tree, listed in descending order (from most general to most specific).
"industry": [
{
"id": "011-000-000-000",
"name": "Retail",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
},
{
"id": "011-018-000-000",
"name": "General Goods",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
},
{
"id": "011-018-002-000",
"name": "Department Stores",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
}
],
// An assessment of how confident we are that this counterparty was involved in this transaction
"matchScore": 93.6,
// The specific location at which this transaction took place. This list can currently contain up to one location.
"location": [
{
// This is a unique ID associated with this location. We recommend building location-specific rules and/or mappings using this ID.
"id": "380e18b7-bf9e-3545-b27e-80e36301c540",
"address": "1590 Dunlawton Ave",
"city": "Port Orange",
"region": "FL",
"postalCode": "32127",
"country": "USA",
"phoneNumber": "+13867562711",
"latitude": 29.116576,
"longitude": -81.02062
}
],
// The counterparty's logo
"logo": "https://v1.spadeapi.com/logos/verified/walmart.png?size=large",
// The median amount of money spent per transaction at this counterparty
"medianSpendPerTransaction": 22.77,
// The counterparty's phone number (if this counterparty has multiple locations, this will generally be its corporate phone number)
"phoneNumber": "+18004386278",
"website": "walmart.com"
}
]
enrichmentId
The enrichmentId
is Spade's unique identifier for this enrichment. You'll want to store this value. Among other uses, you can use it to report issues with the specific enrichment via the error reporting endpoint.
"enrichmentId": "78ba8476-fbe8-48cc-bbd0-1756a0eef0e3"
When should I call Spade's API?
Most of our customers call our API during the auth flow, and we recommend you do too.
Getting the most value out of your enrichment
Let's go over what we've accomplished.
A) We've enriched our first transaction
B) Based on the enriched data, we now know some basics of the transaction:
- This transaction represents a card purchase of $42 at a Walmart on 1590 Dunlawton Ave in Port Orange, Florida.
- Walmart's website is
walmart.com
and their logo can be fetched from Spade's CDN athttps://v1.spadeapi.com/logos/verified/walmart.png?size=large
. - This particular transaction was processed by Square. Square is acting as a payment processor, and its logo can be fetched from Spade's CDN at
https://static.v2.spadeapi.com/logos/8fbe0c0be54a35a8b8ff0d982c84fc55/light.png
. - This transaction belongs to the "Department Stores" category. This category's logo can be fetched from Spade's CDN at
https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png
However, there's a lot of additional information that can provide even more value from your enrichment. Spade's API returns fields including:
Transaction Information
- Third Parties: Information on any entity besides the counterparty involved in a transaction but not a direct recipient
- Type: BNPL, delivery service, marketplace, payment processor, platform, or point-of-sale system
- Third party ID: a proprietary and unique Spade identifier for the third party
- Cleaned third party name and third party logo
- Channel: Spade’s assessment of whether the transaction was at a digital or physical merchant (separate from CNP / CP)
Counterparty Information
- Cleaned merchant name, logo, website, and phone number
- Counterparty ID: a proprietary and unique Spade identifier for the merchant (e.g., all Starbucks have the same counterparty ID even if they have different acquirer IDs)
- Industry: custom categorization system operating alongside MCC codes but more accurately categorizing a merchant (in tree form with increasing specificity). See the Glossary for more information.
- Channel: Spade’s assessment of whether the transaction was at a digital or physical merchant (separate from CNP / CP)
- Geographic data:
- Location ID: a proprietary and unique Spade identifier for the exact location of the merchant
- Latitude, longitude, address, city, state, postal code, and country for the exact location of the merchant
- Match score: a numerical predictor generated by Spade to assess how likely the transaction is to have occurred at the counterparty identified. Scores range from 0 (lowest likelihood) - 100 (highest likelihood). No match is returned if match score is below 50, and Spade provides guidance on additional thresholds to set depending on use case.
See the API Reference for a full list of fields returned via the Spade card transaction enrichment API.
Matches vs. Non-Matches
Spade has industry leading match rates; however, due to the constantly changing nature of merchant data, matching on 100% of transactions is nearly impossible. We constantly work to improve our match rate, however, for many transactions, it is not possible to identify the counterparty and/or location at which the transaction took place. In these cases, we will still extract as much information as possible from the raw transaction and return it in the enrichment.
Let's take a quick look at a transaction that doesn't match (for this example, we've made up a company that doesn't exist).
import requests
raw_transaction = {
"occurredAt": "2023-03-14T01:42:00Z",
"acquirerId": "123456789",
"merchantName": "MAD HATTER SPORTS CO",
"transactionId": "166c5ad8-8a94-4964-a659-03cdb64525f2",
"userId": "f841399e-d095-4e7f-b004-c39d7e3fa329",
"categoryCode": "5469",
"categoryType": "MCC",
"amount": "42.00",
"currencyCode": "USD",
"location": {
"city": "800-123-4567",
"region": "TX",
"country": "USA"
}
}
response = requests.post("https://east.sandbox.spade.com/transactions/enrich", json=raw_transaction, headers={"X-Api-Key": "<Your API Key Here>"})
enriched_transaction = response.json()
print(enriched_transaction)
Sending the above request returns:
{
"transactionInfo": {
"type": "spending",
"thirdParties": [],
"spendingInfo": {
"channel": {
"value": null
}
}
},
"counterparty": [
{
"id": null,
"name": "Mad Hatter Sports Co",
"legalName": "MAD HATTER SPORTS CO",
"industry": [
{
"id": "011-000-000-000",
"name": "Retail",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
},
{
"id": "011-013-000-000",
"name": "Specialty Retail",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
},
{
"id": "011-013-019-000",
"name": "Sporting Goods",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
}
],
"matchScore": null,
"location": [
{
"id": null,
"address": null,
"city": null,
"region": "TX",
"postalCode": null,
"country": "USA",
"phoneNumber": "+18001234567",
"latitude": null,
"longitude": null
}
],
"logo": null,
"medianSpendPerTransaction": null,
"phoneNumber": null,
"website": null
}
],
"enrichmentId": "0ff549ef-afc2-490b-bf09-fcbef9b86915"
}
When we are unable to find a counterparty match, the counterparty ID and matchScore
will both be null
. However, we will still clean the merchant name, sort the data (e.g., put the phone number in the correct field), and provide an industry.
Similarly, when we are unable to find a location match, the location ID will be null
(even when we identify the counterparty, we don't always identify a specific location).
Implementation notes
Our endpoints only accept JSON content. If you're having issues with the content type, please ensure that the
Content-Type
header is set toapplication/json
(some http clients usemultipart/form-data
by default).
Errors are rare, but you should make sure you handle them properly. The most common errors to look out for are:
- 400 - These occur if, for instance, a required field like
merchantName
ends up missing from a particular transaction. In this case, we won't be able to provide an enrichment since there was something wrong with the incoming data.- 500 - These are much more rare but can occur if, for instance, our infrastructure provider (AWS) is having issues. Our engineering team is automatically alerted in the rare case that 500 errors occur.