← Blog & Resources

VaultSpend Multi-Card Management - Creating Ad Spend Cards with Per-Card Limits and Risk Isolation

EN only

In the highvelocity world of digital advertising, agility is everything. Media buyers need to spin up campaigns instantly, test new traffic sources, and scale w

Published July 6, 2026 · ThisKard team

In the high-velocity world of digital advertising, agility is everything. Media buyers need to spin up campaigns instantly, test new traffic sources, and scale what works. However, behind every successful campaign lies a critical infrastructure challenge: payment logistics.

Relying on a single corporate card for multiple ad accounts is a ticking time bomb. If one ad account triggers a fraud flag or gets banned, the associated card is often frozen by the payment processor, halting all ad spend across the business. Conversely, shared cards make reconciliation a nightmare, blurring the lines between Facebook, Google, and TikTok spend.

Today, we are diving into VaultSpend, part of ThisKard’s Sovereign series (B端). VaultSpend is designed specifically for enterprise spend management, allowing developers and operators to programmatically generate virtual cards with granular controls. In this tutorial, we will build a workflow to create isolated ad spend cards, ensuring that a risk event on one platform never impacts another.

Understanding the Sovereign Series Architecture

Before we write code, it is essential to understand where VaultSpend fits in the ThisKard ecosystem. ThisKard offers two distinct product lines:

  1. Global series (C端): Includes Flash, Prime, and Horizon. These are consumer-facing products focused on individual spending, travel, and personal finance.
  2. Sovereign series (B端): Includes CitadelPayroll, VaultSpend, and OnyxClearing. These are business-facing infrastructure products.

VaultSpend distinguishes itself by offering "Card Issuing as a Service." Unlike CitadelPayroll, which focuses on recurring employee disbursements, VaultSpend provides the flexibility required for dynamic operational spending—specifically, the creation of single-use or limited-purpose virtual cards.

The Risk Isolation Strategy

The core concept we are implementing today is compartmentalization. By mapping a unique virtual card to every ad account or campaign, we achieve three things:

  1. Risk Isolation: If an ad account is flagged, only the specific card associated with that account is compromised. The rest of your spend infrastructure remains online.
  2. Spend Limits: You can cap daily or lifetime spend per card, preventing rogue campaigns from draining your ledger.
  3. Clean Reconciliation: Transaction data feeds directly back to the specific ad account ID, simplifying accounting.

Prerequisites

To follow along, ensure you have the following:

  • A ThisKard Business Account: specifically enabled for the Sovereign series.
  • API Keys: You will need a sk_live_ or sk_test_ secret key from your developer dashboard.
  • Environment: Python 3.8+ or Node.js 18+ installed.
  • Ledger Balance: Ensure your VaultSpend master account has funds to provision cards.

Step-by-Step Workflow

We will implement the following workflow:

  1. Authentication: Establish a secure connection to the API.
  2. Ledger Verification: Check available funds in the Sovereign container.
  3. Card Creation: Generate a new virtual card with a specific label and type.
  4. Limit Assignment: Apply strict velocity limits (transaction count and amount) to the card.
  5. MCC Restrictions: (Optional) Restrict the card to Merchant Category Codes (MCCs) relevant to advertising.

Implementation

For this tutorial, we will use Python for its readability and robust handling of JSON data.

1. Setup and Authentication

First, we need to define our base URL and headers. All Sovereign series endpoints are accessible via api.thiskard.com.

import requests
import os
import json
from datetime import datetime

# Configuration
BASE_URL = "https://api.thiskard.com/v1/sovereign"
API_KEY = os.environ.get("THISKARD_SECRET_KEY") # Always use environment variables for secrets

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
    "Idempotency-Key": "" # We will generate this for POST requests
}

2. The Card Creation Logic

We will create a function create_isolated_ad_card. This function will encapsulate the logic for creating the card and setting its limits immediately. This mimics a real-world production flow where you need the card ready for immediate use.

Here is the complete, runnable code block:

import uuid

def create_isolated_ad_card(platform_name, daily_limit_cents, max_transactions):
    """
    Creates a VaultSpend virtual card with specific limits for ad spend isolation.
    
    Args:
        platform_name (str): Name of the ad platform (e.g., 'META_ADS_Q4').
        daily_limit_cents (int): Daily spend limit in cents (e.g., 50000 for $500.00).
        max_transactions (int): Maximum number of transactions allowed per day.
        
    Returns:
        dict: The created card object with sensitive details.
    """
    
    # Generate a unique idempotency key to prevent duplicate creation on retries
    idempotency_key = str(uuid.uuid4())
    headers["Idempotency-Key"] = idempotency_key
    
    # Step 1: Define the Card Payload
    # We use 'VAULT_AD_SPEND' type specifically for advertising use cases.
    card_payload = {
        "product_line": "VAULTSPEND",
        "card_type": "VIRTUAL",
        "label": f"AD_SPEND_{platform_name}_{datetime.now().strftime('%Y%m%d')}",
        "metadata": {
            "purpose": "ad_spend",
            "platform": platform_name,
            "risk_profile": "isolated"
        }
    }
    
    try:
        print(f"Provisioning card for {platform_name}...")
        
        # Step 2: Create the Card
        create_url = f"{BASE_URL}/cards"
        response = requests.post(create_url, json=card_payload, headers=headers)
        
        if response.status_code != 201:
            raise Exception(f"Card creation failed: {response.text}")
            
        card_data = response.json()
        card_id = card_data["id"]
        print(f"Card created successfully. ID: {card_id}")
        
        # Step 3: Apply Limits and Restrictions
        # It is critical to set limits *before* activating the card.
        limits_url = f"{BASE_URL}/cards/{card_id}/limits"
        
        # Define specific MCC codes for advertising to prevent misuse
        # 7311: Advertising Services
        # 7319: Directories/Mailing Lists
        allowed_mccs = [7311, 7319]
        
        limits_payload = {
            "spend_limits": {
                "daily": {
                    "amount": daily_limit_cents,
                    "currency": "USD"
                }
            },
            "velocity_limits": {
                "daily": {
                    "count": max_transactions
                }
            },
            "merchant_controls": {
                "mode": "WHITELIST",
                "mcc_codes": allowed_mccs
            }
        }
        
        print("Applying risk controls and limits...")
        limits_response = requests.post(limits_url, json=limits_payload, headers=headers)
        
        if limits_response.status_code != 200:
            # If limits fail, we should ideally deactivate the card to prevent runaway spend
            print(f"Warning: Failed to set limits. Card {card_id} may be unsafe.")
            raise Exception(f"Limit application failed: {limits_response.text}")
            
        print("Limits applied successfully.")
        
        # Step 4: Activate the Card
        activate_url = f"{BASE_URL}/cards/{card_id}/activate"
        activate_response = requests.post(activate_url, headers=headers)
        
        if activate_response.status_code != 200:
            raise Exception(f"Activation failed: {activate_response.text}")
            
        print(f"Card {card_id} is now ACTIVE and ready for spend.")
        
        return {
            "card_id": card_id,
            "last_four": card_data["last_four"],
            "status": "ACTIVE",
            "daily_limit": daily_limit_cents
        }
        
    except Exception as e:
        print(f"Error during workflow: {e}")
        return None

# --- Execution Example ---

if __name__ == "__main__":
    # Create a card for a new Meta Ads campaign with a $1,000 daily limit
    result = create_isolated_ad_card(
        platform_name="META_Q4_PUSH",
        daily_limit_cents=100000, 
        max_transactions=50
    )
    
    if result:
        print("\n--- Operation Complete ---")
        print(json.dumps(result, indent=2))

Code Walkthrough

  1. Product Line Specification: We explicitly pass product_line: "VAULTSPEND" in the payload. This ensures the card is provisioned under the Sovereign series logic, distinct from Global series consumer cards.
  2. Idempotency Keys: We generate a UUID for the Idempotency-Key header. In distributed systems, network timeouts happen. If you retry a POST request without this key, you might accidentally create two cards and double your liability. ThisKard's API uses this key to ensure the request is processed only once.
  3. MCC Whitelisting: We set merchant_controls to WHITELIST mode with MCCs 7311 and 7319. This is a critical risk mitigation step. If these credentials are leaked or the ad account is compromised, the card cannot be used to buy electronics or gift cards—it can only be used for advertising services.
  4. Activation Sequence: Note that we create the card, set limits, and then activate. This "inactive" window is a security best practice. You never want an active card sitting in the wild without its guardrails in place.

Error Handling and Edge Cases

When integrating financial APIs, robust error handling is not optional—it is the difference between a stable platform and a finance team that cannot reconcile the books. Here are the common errors you will encounter with the api.thiskard.com endpoints and how to handle them.

1. Insufficient Funds (HTTP 402)

When creating a card, VaultSpend may attempt to reserve a small authorization amount or verify the ledger balance.

  • Error: INSUFFICIENT_FUNDS on the Sovereign container.
  • Solution: Implement a webhook listener for the ledger.low_balance event. Automate top-ups from your external bank account to the Sovereign container before the balance hits zero.

2. MCC Validation Failure (HTTP 422)

If you attempt to whitelist an MCC that conflicts with the card's base product type, the API will reject the limit configuration.

  • Error: INVALID_MCC_FOR_PRODUCT.
  • Solution: Refer to the latest ThisKard documentation for supported MCCs per product line. VaultSpend supports a wide range, but certain high-risk categories are blocked at the processor level.

3. Rate Limiting (HTTP 429)

Provisioning hundreds of cards simultaneously (e.g., for a large agency onboarding) can trigger rate limits.

  • Error: RATE_LIMIT_EXCEEDED.
  • Solution: Implement exponential backoff in your retry logic. The Retry-After header in the response will tell you how many seconds to wait.

Best Practices for Operators

The Naming Convention Strategy

In the code, we used a label format: AD_SPEND_{PLATFORM}_{DATE}. While this seems trivial, consistent naming is vital for operators. When your finance team looks at the statement at the end of the month, they shouldn't see generic labels like "Card 1234". They should see "AD_SPEND_META_Q4". This allows for instant identification and reduces reconciliation time from hours to minutes.

Lifecycle Management

Cards are not "set it and forget it" assets.

  1. Rotation: Establish a policy to rotate cards every 90 days. This limits the exposure window if card data is exfiltrated.
  2. Deactivation: Use the DELETE /cards/{id} endpoint immediately when an ad account is closed or a campaign ends. This frees up the card slot count in your subscription and reduces the attack surface.

Webhook Integration

Do not rely solely on polling the API to check transaction status. Subscribe to the transaction.settled and card.frozen webhooks.

  • Scenario: An ad platform processes a refund.
  • Action: The webhook triggers, your system updates the local ledger balance in real-time, allowing you to reallocate those funds to a different campaign immediately.

Conclusion

Managing ad spend at scale requires a infrastructure mindset. By leveraging ThisKard's VaultSpend API, you move away from the fragility of shared corporate cards to a robust, programmable system of isolated payment rails.

We have successfully created a Python script that authenticates, provisions a card, secures it with MCC whitelists and spend limits, and activates it for use. This implementation provides the foundation for a secure, scalable ad spend operation where risk is contained, and financial data remains pristine.

Ready to start? Visit thiskard.com to learn more.