User Category Personalization Guide
ⓘ Reading Time: 15 mins
Category personalization is released in beta.
Category personalization makes it easy to customize Spade's categorization system to support additional use cases. Key features include:
- Creating custom categories at the integration-level
- Creating custom categories at the user-level
- Recategorizing individual transactions with default and/or custom categories
- Recategorizing future transactions with default and/or custom categories based on the counterparty
This guide walks you through creating custom categories and recategorizing transactions at the user-level. information on creating integration-level personalizations, please see the Category Personalization Guide.
Category personalization is not enabled by default. To request access, please contact us at [email protected].
For simplicity, the examples in this guide show you how to send requests to Spade directly. However, you will likely want to build user category personalization into client applications. Because client-side code is public and your API key is secret, you will need to proxy user category personalization requests through your backend to Spade's servers. The Merchant Search Guide demonstrates how to proxy requests through your backend to Spade's API.
⚠ NEVER send your API key to the client. This includes any client-side application code bundles (websites, mobile apps, etc...).
Fetch the default categories for your integration
The first thing you’ll likely want to do is fetch the default categories for your integration. This list contains all of the categories that Spade provides, plus any custom categories that you’ve added on an integration-wide level.
import requests
response = requests.get("https://east.sandbox.spade.com/categories", headers={"X-Api-Key": "<Your API Key Here>"})
print(response.json())
Sending the above request returns a list containing all of Spade's 250+ categories, plus any custom categories that you’ve added on an integration-wide level.
[
// Spade's default categories will show up first
{
"id": "001-000-000-000",
"name": "Banking and Finance",
"icon": "https://static.v2.spadeapi.com/categories/61897b3a5af545bab45ca1bf20498e65/light.png",
"fullCategoryHierarchy": [
{
"id": "001-000-000-000",
"name": "Banking and Finance",
"icon": "https://static.v2.spadeapi.com/categories/61897b3a5af545bab45ca1bf20498e65/light.png"
}
]
},
{
"id": "001-001-000-000",
"name": "Accounting and Bookkeeping",
"icon": "https://static.v2.spadeapi.com/categories/61897b3a5af545bab45ca1bf20498e65/light.png",
"fullCategoryHierarchy": [
{
"id": "001-000-000-000",
"name": "Banking and Finance",
"icon": "https://static.v2.spadeapi.com/categories/61897b3a5af545bab45ca1bf20498e65/light.png"
},
{
"id": "001-001-000-000",
"name": "Accounting and Bookkeeping",
"icon": "https://static.v2.spadeapi.com/categories/61897b3a5af545bab45ca1bf20498e65/light.png"
}
]
},
...
// Your integration's custom categories will show up next
{
"id": "7235be6a-669c-47f2-9ab6-cac3f3edbab9",
"name": "Family",
"icon": null,
"fullCategoryHierarchy": [
{
"id": "7235be6a-669c-47f2-9ab6-cac3f3edbab9",
"name": "Family",
"icon": null
}
]
},
{
"id": "ba8d4e26-052a-4260-bcf4-6523469fcf48",
"name": "Day Care",
"icon": null,
"fullCategoryHierarchy": [
{
"id": "7235be6a-669c-47f2-9ab6-cac3f3edbab9",
"name": "Family",
"icon": null
},
{
"id": "ba8d4e26-052a-4260-bcf4-6523469fcf48",
"name": "Day Care",
"icon": null
}
]
}
]
Note that Spade’s categories are hierarchical, so Accounting and Bookkeeping
, for instance, sits underneath the Banking and Finance
category, which sits at the root level. For convenience, each serialized category includes a fullCategoryHierarchy
object, which contains the full hierarchy of the category.
Creating a custom user category
As with default categories and custom integration-wide categories, custom user categories are hierarchical. They can sit at the root level, under Spade's categories, under custom integration-level categories, or under other custom user-level categories. For instance, here’s how you can create a custom user category that sits at the root level:
import requests
custom_category = {
"name": "Kitchen Remodel 2024",
"parentId": ""
}
response = requests.post("https://east.sandbox.spade.com/users/1234/categories", json=custom_category, headers={"X-Api-Key": "<Your API Key Here>"})
print(response.json())
Sending the above request creates a new custom user category and returns a copy of the serialized category:
{
"id": "9fb31902-1f80-47a9-b717-cc3b1db0ad1f",
"name": "Kitchen Remodel 2024",
"icon": null,
"fullCategoryHierarchy": [
{
"id": "9fb31902-1f80-47a9-b717-cc3b1db0ad1f",
"name": "Kitchen Remodel 2024",
"icon": null
}
]
}
Here’s how you can create a custom user category that sits under this category:
import requests
custom_category = {
"name": "Hardware",
"parentId": "9fb31902-1f80-47a9-b717-cc3b1db0ad1f" # Replace with the ID of the category you just created
}
response = requests.post("https://east.sandbox.spade.com/users/1234/categories", json=custom_category, headers={"X-Api-Key": "<Your API Key Here>"})
print(response.json())
Sending the above request creates the new custom user category and returns a copy of the serialized category:
{
"id": "6bf9b0cd-20b5-4024-9dc2-446af3bda72c",
"name": "Hardware",
"icon": null,
"fullCategoryHierarchy": [
{
"id": "9fb31902-1f80-47a9-b717-cc3b1db0ad1f",
"name": "Kitchen Remodel 2024",
"icon": null
},
{
"id": "6bf9b0cd-20b5-4024-9dc2-446af3bda72c",
"name": "Hardware",
"icon": null
}
]
}
Fetching custom user categories
In order to support curated user experiences, you’ll likely want to fetch custom user categories whenever you fetch the default categories for your integration. Here’s how you can fetch custom user categories:
response = requests.get("https://east.sandbox.spade.com/users/1234/categories", headers={"X-Api-Key": "<Your API Key Here>"})
print(response.json())
Sending the above request returns:
[
{
"id": "9fb31902-1f80-47a9-b717-cc3b1db0ad1f",
"name": "Kitchen Remodel 2024",
"icon": null,
"fullCategoryHierarchy": [
{
"id": "9fb31902-1f80-47a9-b717-cc3b1db0ad1f",
"name": "Kitchen Remodel 2024",
"icon": null
}
]
},
{
"id": "6bf9b0cd-20b5-4024-9dc2-446af3bda72c",
"name": "Hardware",
"icon": null,
"fullCategoryHierarchy": [
{
"id": "9fb31902-1f80-47a9-b717-cc3b1db0ad1f",
"name": "Kitchen Remodel 2024",
"icon": null
},
{
"id": "6bf9b0cd-20b5-4024-9dc2-446af3bda72c",
"name": "Hardware",
"icon": null
}
]
}
]
Now that you have both the default and custom categories, you can combine them to create a list containing all of the categories that the user has access to:
all_categories = [*categories, *user_categories]
If you’re building a UX such as a transaction feed, you can then feed all_categories
to the frontend and display them as a tree, a searchable input, etc…
Recategorizing a specific transaction for a specific user
To recategorize a specific transaction, you’ll want to update that transaction record in your internal system. For instance:
import requests
# Update each transaction's category in your internal system.
# Note that the PATCH body will depend on your internal data schema.
requests.patch(
"https://your.backend.com/enriched-transactions/1234",
{
"category": [
{
"id": "9fb31902-1f80-47a9-b717-cc3b1db0ad1f",
"name": "Kitchen Remodel 2024",
"icon": null
},
{
"id": "6bf9b0cd-20b5-4024-9dc2-446af3bda72c",
"name": "Hardware",
"icon": null
}
]
},
headers=YOUR_AUTH_HEADERS,
)
Recategorizing all future transactions for a specific counterparty
One of the most powerful features Spade provides is the ability for users to recategorize future transactions before they take place. This feature takes advantage of Spade’s ability to consistently match transactions to stable counterparty IDs using ground truth data.
Here’s how a user can recategorize future transactions for a specific counterparty:
counterparty_category_personalization = {
# Lowe's
"counterpartyId": "83aa2f0a-bd1e-4613-807d-6b6f4bb39b4c",
# Hardware
"categoryId": "6bf9b0cd-20b5-4024-9dc2-446af3bda72c"
}
requests.put("https://east.sandbox.spade.com/users/1234/counterparty-category-personalization", json=counterparty_category_personalization, headers={"X-Api-Key": "<Your API Key Here>"})
Note that user-level personalizations take precedence over integration-level personalizations, so if you've created both a user-level personalization and an integration-level personalization for the same counterparty, the enrichment API will only use the user-level personalization.
With this personalization in place, any future transactions that take place at Lowe's
for this specific user will be enriched with the custom category, which will appear in the personalization
section of the enrichment as the counterparty's industry
:
{
"transactionInfo": {
"type": "spending",
"thirdParties": [],
"spendingInfo": {
"channel": {
"value": "physical"
}
},
"transactionId": "6d315cc3-3c9e-47be-9711-d84b4b1c21c9",
"irregularWebPresenceDetected": false,
"recurrenceInfo": null
},
"counterparty": [
{
"id": "83aa2f0a-bd1e-4613-807d-6b6f4bb39b4c",
"name": "Lowe's",
"legalName": "Lowe's Companies, Inc.",
// Spade still returns the original industry here so you can use it for internal analysis
"industry": [
{
"id": "011-000-000-000",
"name": "Retail",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
},
{
"id": "011-007-000-000",
"name": "Hardware and Home Improvement",
"icon": "https://static.v2.spadeapi.com/categories/ee4ee39fd5474d31ac42f9e606b9040a/light.png"
}
],
"location": [
{
"id": "f39d9c63-3be5-390e-b349-ee993fda44b1",
"address": "1801 Fordham Blvd",
"addressLine1": "1801 Fordham Blvd",
"addressLine2": null,
"city": "Chapel Hill",
"region": "NC",
"postalCode": "27514",
"country": "USA",
"phoneNumber": "+19199673289",
"latitude": 35.94765,
"longitude": -79.013007,
"matchScore": 91.67
}
],
"matchScore": 88.79,
"logo": "https://static.v2.spadeapi.com/logos/83aa2f0abd1e4613807d6b6f4bb39b4c/light.png",
"medianSpendPerTransaction": null,
"phoneNumber": null,
"website": "lowes.com"
}
],
"personalization": {
"counterparty": [
{
"id": "83aa2f0a-bd1e-4613-807d-6b6f4bb39b4c",
// Here's the personalized merchant category
"industry": [
{
"id": "9fb31902-1f80-47a9-b717-cc3b1db0ad1f",
"name": "Kitchen Remodel 2024",
"icon": null
},
{
"id": "6bf9b0cd-20b5-4024-9dc2-446af3bda72c",
"name": "Hardware",
"icon": null
}
]
}
]
},
"enrichmentId": "c4ca89ce-4fe0-4ed0-93e0-09dc4d74cba5"
}
Deleting custom user-level categories
You can delete custom user-level categories all at once or individually.
To delete all custom user-level categories, send a DELETE
request to the /users/:userId/categories
endpoint:
import requests
requests.delete("https://east.sandbox.spade.com/users/1234/categories", headers={"X-Api-Key": "<Your API Key Here>"})
To delete a specific custom user-level category, send a DELETE
request to the /users/:userId/categories/:id
endpoint with the category's ID:
import requests
requests.delete("https://east.sandbox.spade.com/users/1234/categories/77f376cf-ec09-47a5-b90b-7406bb018dc9", headers={"X-Api-Key": "<Your API Key Here>"})
Any custom user-level categories that were children of the deleted user-level categories will automatically have their
parentId
set to an empty string (i.e. they will become root-level categories).
Deleting user-level counterparty category personalizations
You can delete user-level counterparty category personalizations all at once or individually.
To delete all user-level counterparty category personalizations, send a DELETE
request to the /users/:userId/counterparty-category-personalizations
endpoint:
import requests
requests.delete("https://east.sandbox.spade.com/users/1234/counterparty-category-personalizations", headers={"X-Api-Key": "<Your API Key Here>"})
To delete a specific user-level counterparty category personalization, send a DELETE
request to the /users/:userId/counterparty-category-personalizations/:counterpartyId
endpoint with the counterpartyId
of the personalization you want to delete:
import requests
requests.delete("https://east.sandbox.spade.com/users/1234/counterparty-category-personalizations/4ad9e96c-b8a4-4421-88fe-112ac23e37cc", headers={"X-Api-Key": "<Your API Key Here>"})
Conclusion
You've just learned how Spade's category personalization endpoints can be used to create custom categories at the user-level and recategorize transactions onto those categories.