CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-stripe

Stripe API wrapper for Node.js providing comprehensive payment processing, subscription management, and financial services integration.

Pending
Overview
Eval results
Files

issuing.mddocs/

Issuing

Stripe Issuing enables you to create, manage, and control corporate cards. This comprehensive card issuing platform provides capabilities for virtual and physical card creation, real-time authorization controls, transaction monitoring, and dispute management.

Card Management

Issuing.Cards

Create and manage virtual and physical cards:

interface IssuingCard {
  id: string;
  object: 'issuing.card';
  cardholder: string;
  type: 'virtual' | 'physical';
  status: 'active' | 'inactive' | 'canceled' | 'lost' | 'stolen';
  brand: 'visa' | 'mastercard';
  currency: string;
  spending_controls: {
    allowed_categories?: string[];
    blocked_categories?: string[];
    spending_limits?: Array<{
      amount: number;
      categories?: string[];
      interval: 'per_authorization' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'all_time';
    }>;
  };
  created: number;
  exp_month: number;
  exp_year: number;
  last4: string;
}

// Create virtual card
const virtualCard = await stripe.issuing.cards.create({
  cardholder: 'ich_cardholder_123',
  currency: 'usd',
  type: 'virtual',
  spending_controls: {
    spending_limits: [
      {
        amount: 50000, // $500 limit
        interval: 'monthly'
      }
    ],
    allowed_categories: ['fuel_and_gas_stations', 'restaurants']
  },
  metadata: {
    employee_id: 'emp_123',
    department: 'marketing'
  }
});

// Create physical card
const physicalCard = await stripe.issuing.cards.create({
  cardholder: 'ich_cardholder_456',
  currency: 'usd',
  type: 'physical',
  shipping: {
    address: {
      line1: '123 Main St',
      city: 'San Francisco',
      state: 'CA',
      postal_code: '94105',
      country: 'US'
    },
    name: 'John Doe',
    service: 'standard'
  },
  spending_controls: {
    spending_limits: [
      {
        amount: 100000, // $1,000 monthly limit
        interval: 'monthly'
      },
      {
        amount: 5000, // $50 per transaction
        interval: 'per_authorization'
      }
    ]
  }
});

// Create card with category restrictions
const restrictedCard = await stripe.issuing.cards.create({
  cardholder: 'ich_cardholder_789',
  currency: 'usd',
  type: 'virtual',
  spending_controls: {
    blocked_categories: [
      'gambling',
      'adult_digital_goods',
      'liquor_stores'
    ],
    allowed_categories: [
      'gas_stations',
      'grocery_stores',
      'restaurants',
      'office_supplies'
    ]
  }
});

// Retrieve card
const retrieved = await stripe.issuing.cards.retrieve('ic_123', {
  expand: ['cardholder']
});

// Update card
const updated = await stripe.issuing.cards.update('ic_123', {
  status: 'inactive',
  spending_controls: {
    spending_limits: [
      {
        amount: 25000, // Reduced to $250 monthly
        interval: 'monthly'
      }
    ]
  },
  metadata: {
    status_reason: 'employee_left'
  }
});

// List cards
const cards = await stripe.issuing.cards.list({
  cardholder: 'ich_cardholder_123',
  status: 'active',
  limit: 20
});

// List cards by type
const physicalCards = await stripe.issuing.cards.list({
  type: 'physical',
  status: 'active'
});

Issuing.Cardholders

Manage individuals authorized to use issued cards:

interface IssuingCardholder {
  id: string;
  object: 'issuing.cardholder';
  type: 'individual' | 'company';
  name: string;
  email?: string;
  phone_number?: string;
  status: 'active' | 'inactive' | 'blocked';
  billing: {
    address: Address;
  };
  individual?: {
    first_name: string;
    last_name: string;
    dob?: {
      day: number;
      month: number;
      year: number;
    };
    verification?: {
      document?: {
        back?: string;
        front?: string;
      };
    };
  };
  company?: {
    tax_id?: string;
  };
}

// Create individual cardholder
const individual = await stripe.issuing.cardholders.create({
  type: 'individual',
  name: 'John Doe',
  email: 'john.doe@company.com',
  phone_number: '+15555551234',
  billing: {
    address: {
      line1: '123 Main St',
      line2: 'Apt 4B',
      city: 'San Francisco',
      state: 'CA',
      postal_code: '94105',
      country: 'US'
    }
  },
  individual: {
    first_name: 'John',
    last_name: 'Doe',
    dob: {
      day: 15,
      month: 6,
      year: 1990
    }
  }
});

// Create company cardholder
const company = await stripe.issuing.cardholders.create({
  type: 'company',
  name: 'Acme Corp Employee Cards',
  email: 'finance@acme.com',
  billing: {
    address: {
      line1: '456 Business Ave',
      city: 'New York',
      state: 'NY',
      postal_code: '10001',
      country: 'US'
    }
  },
  company: {
    tax_id: '123456789'
  }
});

// Create cardholder with identity verification
const verifiedCardholder = await stripe.issuing.cardholders.create({
  type: 'individual',
  name: 'Jane Smith',
  email: 'jane.smith@company.com',
  billing: {
    address: {
      line1: '789 Oak St',
      city: 'Austin',
      state: 'TX',
      postal_code: '73301',
      country: 'US'
    }
  },
  individual: {
    first_name: 'Jane',
    last_name: 'Smith',
    verification: {
      document: {
        front: 'file_identity_front',
        back: 'file_identity_back'
      }
    }
  }
});

// Retrieve cardholder
const retrieved = await stripe.issuing.cardholders.retrieve('ich_123');

// Update cardholder
const updated = await stripe.issuing.cardholders.update('ich_123', {
  email: 'newemail@company.com',
  phone_number: '+15555559999',
  status: 'inactive'
});

// List cardholders
const cardholders = await stripe.issuing.cardholders.list({
  status: 'active',
  limit: 20
});

// List cardholders by type
const individuals = await stripe.issuing.cardholders.list({
  type: 'individual',
  email: 'john@company.com'
});

Transaction Management

Issuing.Transactions

Monitor and manage card transactions:

interface IssuingTransaction {
  id: string;
  object: 'issuing.transaction';
  card: string;
  cardholder?: string;
  type: 'capture' | 'refund';
  amount: number;
  currency: string;
  authorization?: string;
  merchant_data: {
    category: string;
    name: string;
    network_id: string;
    city?: string;
    country?: string;
  };
  purchase_details?: {
    flight?: FlightDetails;
    fuel?: FuelDetails;
    lodging?: LodgingDetails;
    receipt?: ReceiptDetails[];
  };
  created: number;
  status: 'pending' | 'posted';
}

// Retrieve transaction
const transaction = await stripe.issuing.transactions.retrieve('ipi_123', {
  expand: ['card', 'cardholder']
});

// Update transaction
const updated = await stripe.issuing.transactions.update('ipi_123', {
  metadata: {
    category: 'travel',
    expense_report_id: 'exp_456'
  }
});

// List transactions
const transactions = await stripe.issuing.transactions.list({
  card: 'ic_123',
  limit: 50
});

// List transactions by date range
const recentTransactions = await stripe.issuing.transactions.list({
  cardholder: 'ich_123',
  created: {
    gte: Math.floor(Date.now() / 1000) - 86400 * 30 // Last 30 days
  }
});

// List transactions by merchant category
const restaurantTransactions = await stripe.issuing.transactions.list({
  card: 'ic_123',
  'merchant_data[category]': 'restaurants'
});

Issuing.Authorizations

Manage real-time authorization decisions:

interface IssuingAuthorization {
  id: string;
  object: 'issuing.authorization';
  card: string;
  cardholder?: string;
  amount: number;
  currency: string;
  status: 'pending' | 'closed' | 'reversed';
  approved: boolean;
  authorization_method: 'chip' | 'contactless' | 'keyed_in' | 'swipe' | 'online';
  merchant_data: {
    category: string;
    name: string;
    network_id: string;
    city?: string;
    country?: string;
  };
  verification_data: {
    address_line1_check?: 'match' | 'mismatch' | 'not_provided';
    address_postal_code_check?: 'match' | 'mismatch' | 'not_provided';
    cvc_check?: 'match' | 'mismatch' | 'not_provided';
  };
}

// Retrieve authorization
const authorization = await stripe.issuing.authorizations.retrieve('iauth_123', {
  expand: ['card', 'cardholder']
});

// Approve authorization
const approved = await stripe.issuing.authorizations.approve('iauth_123', {
  amount: 5000 // Approve for $50
});

// Decline authorization
const declined = await stripe.issuing.authorizations.decline('iauth_123', {
  reason: 'insufficient_funds'
});

// Update authorization
const updated = await stripe.issuing.authorizations.update('iauth_123', {
  metadata: {
    approval_reason: 'manual_review_approved',
    reviewer: 'admin_123'
  }
});

// List authorizations
const authorizations = await stripe.issuing.authorizations.list({
  card: 'ic_123',
  status: 'pending',
  limit: 20
});

// List declined authorizations
const declined = await stripe.issuing.authorizations.list({
  cardholder: 'ich_123',
  approved: false
});

Dispute Management

Issuing.Disputes

Handle disputes for issued card transactions:

interface IssuingDispute {
  id: string;
  object: 'issuing.dispute';
  transaction: string;
  status: 'unsubmitted' | 'submitted' | 'won' | 'lost' | 'expired';
  reason: 'fraudulent' | 'subscription_canceled' | 'product_unacceptable' | 'product_not_received' | 'unrecognized' | 'duplicate' | 'credit_not_processed' | 'general' | 'incorrect_amount' | 'canceled_recurring' | 'paid_by_other_means' | 'emv_liability_shift';
  amount: number;
  currency: string;
  evidence: {
    fraudulent?: {
      dispute_explanation?: string;
      uncategorized_file?: string;
    };
    other?: {
      dispute_explanation?: string;
      uncategorized_file?: string;
    };
  };
}

// Create dispute
const dispute = await stripe.issuing.disputes.create({
  transaction: 'ipi_transaction_123',
  reason: 'fraudulent',
  evidence: {
    fraudulent: {
      dispute_explanation: 'This transaction was not authorized by the cardholder.',
      uncategorized_file: 'file_evidence_123'
    }
  }
});

// Create product dispute
const productDispute = await stripe.issuing.disputes.create({
  transaction: 'ipi_transaction_456',
  reason: 'product_not_received',
  evidence: {
    other: {
      dispute_explanation: 'Product was never delivered despite payment.',
      uncategorized_file: 'file_shipping_evidence'
    }
  }
});

// Retrieve dispute
const retrieved = await stripe.issuing.disputes.retrieve('idp_123');

// Update dispute evidence
const updated = await stripe.issuing.disputes.update('idp_123', {
  evidence: {
    fraudulent: {
      dispute_explanation: 'Updated explanation with additional details.',
      uncategorized_file: 'file_additional_evidence'
    }
  }
});

// List disputes
const disputes = await stripe.issuing.disputes.list({
  status: 'unsubmitted',
  limit: 20
});

// List disputes by transaction
const transactionDisputes = await stripe.issuing.disputes.list({
  transaction: 'ipi_123'
});

// Submit dispute
const submitted = await stripe.issuing.disputes.submit('idp_123');

Physical Card Design

Issuing.PersonalizationDesigns

Customize physical card appearance:

interface IssuingPersonalizationDesign {
  id: string;
  object: 'issuing.personalization_design';
  physical_bundle: string;
  name: string;
  status: 'active' | 'inactive' | 'rejected' | 'requires_review';
  card_logo?: string;
  carrier_text?: {
    footer_body?: string;
    footer_title?: string;
    header_body?: string;
    header_title?: string;
  };
  lookup_key?: string;
}

// Create personalization design
const design = await stripe.issuing.personalizationDesigns.create({
  physical_bundle: 'pb_standard_visa',
  name: 'Company Branded Design',
  card_logo: 'file_company_logo',
  carrier_text: {
    header_title: 'Welcome to Acme Corp',
    header_body: 'Your corporate card',
    footer_title: 'Questions?',
    footer_body: 'Call 1-800-ACME-123'
  },
  lookup_key: 'acme_standard_design'
});

// Retrieve personalization design
const retrieved = await stripe.issuing.personalizationDesigns.retrieve('pd_123');

// Update personalization design
const updated = await stripe.issuing.personalizationDesigns.update('pd_123', {
  name: 'Updated Company Design',
  carrier_text: {
    header_title: 'Acme Corporation',
    footer_body: 'Support: support@acme.com'
  }
});

// List personalization designs
const designs = await stripe.issuing.personalizationDesigns.list({
  status: 'active',
  limit: 10
});

// Activate design
const activated = await stripe.issuing.personalizationDesigns.activate('pd_123');

// Deactivate design
const deactivated = await stripe.issuing.personalizationDesigns.deactivate('pd_123');

// Reject design
const rejected = await stripe.issuing.personalizationDesigns.reject('pd_123', {
  rejection_reasons: {
    card_logo: ['geographic_location']
  }
});

Issuing.PhysicalBundles

Available physical card templates:

interface IssuingPhysicalBundle {
  id: string;
  object: 'issuing.physical_bundle';
  name: string;
  type: 'custom' | 'standard';
  status: 'active' | 'inactive' | 'review';
  features: {
    card_logo: 'optional' | 'required' | 'unsupported';
    carrier_text: 'optional' | 'required' | 'unsupported';
    second_line: 'optional' | 'required' | 'unsupported';
  };
}

// Retrieve physical bundle
const bundle = await stripe.issuing.physicalBundles.retrieve('pb_123');

// List available physical bundles
const bundles = await stripe.issuing.physicalBundles.list({
  status: 'active'
});

// Filter bundles by features
const logoSupportedBundles = bundles.data.filter(
  bundle => bundle.features.card_logo !== 'unsupported'
);

Token Management

Issuing.Tokens

Manage digital wallet tokens:

interface IssuingToken {
  id: string;
  object: 'issuing.token';
  card: string;
  status: 'active' | 'inactive' | 'suspended';
  wallet_provider: 'apple_pay' | 'google_pay' | 'samsung_pay';
  device_fingerprint?: string;
  network_data?: {
    device?: {
      device_id?: string;
      ip_address?: string;
      location?: string;
    };
    wallet?: {
      account_id?: string;
    };
  };
}

// Retrieve token
const token = await stripe.issuing.tokens.retrieve('it_123');

// Update token
const updated = await stripe.issuing.tokens.update('it_123', {
  status: 'suspended'
});

// List tokens
const tokens = await stripe.issuing.tokens.list({
  card: 'ic_123',
  status: 'active'
});

// List tokens by wallet provider
const applePayTokens = await stripe.issuing.tokens.list({
  wallet_provider: 'apple_pay'
});

Test Helpers

TestHelpers.Issuing

Simulate issuing scenarios in test mode:

// Test card delivery
const delivered = await stripe.testHelpers.issuing.deliverCard('ic_test_123');

// Test card failure
const failed = await stripe.testHelpers.issuing.failCard('ic_test_123');

// Test card return
const returned = await stripe.testHelpers.issuing.returnCard('ic_test_123');

// Test card shipping
const shipped = await stripe.testHelpers.issuing.shipCard('ic_test_123');

// Test authorization capture
const captured = await stripe.testHelpers.issuing.capture('iauth_test_123', {
  capture_amount: 1000
});

// Test authorization expiry
const expired = await stripe.testHelpers.issuing.expire('iauth_test_123');

// Test authorization increment
const incremented = await stripe.testHelpers.issuing.increment('iauth_test_123', {
  increment_amount: 500,
  is_amount_controllable: true
});

// Test authorization reversal
const reversed = await stripe.testHelpers.issuing.reverse('iauth_test_123', {
  reverse_amount: 2000
});

// Test transaction creation (force capture)
const forceCapture = await stripe.testHelpers.issuing.createForceCapture({
  card: 'ic_test_123',
  amount: 3000,
  currency: 'usd',
  merchant_data: {
    category: 'restaurants',
    name: 'Test Restaurant',
    network_id: 'test_merchant_123'
  }
});

// Test unlinked refund
const unlinkedRefund = await stripe.testHelpers.issuing.createUnlinkedRefund({
  card: 'ic_test_123',
  amount: 1500,
  currency: 'usd'
});

// Test transaction refund
const refunded = await stripe.testHelpers.issuing.refund('ipi_test_123', {
  refund_amount: 1000
});

Integration Examples

Real-time Authorization Control

// Webhook handler for authorization requests
app.post('/issuing-webhook', async (req, res) => {
  const event = req.body;
  
  if (event.type === 'issuing_authorization.request') {
    const authorization = event.data.object;
    
    // Custom authorization logic
    const shouldApprove = await evaluateAuthorization(authorization);
    
    if (shouldApprove) {
      await stripe.issuing.authorizations.approve(authorization.id);
    } else {
      await stripe.issuing.authorizations.decline(authorization.id, {
        reason: 'spending_controls'
      });
    }
  }
  
  res.status(200).send('OK');
});

async function evaluateAuthorization(auth) {
  // Check spending limits
  const monthlySpend = await getMonthlySpending(auth.card);
  if (monthlySpend + auth.amount > MONTHLY_LIMIT) {
    return false;
  }
  
  // Check merchant category
  const blockedCategories = ['gambling', 'adult_digital_goods'];
  if (blockedCategories.includes(auth.merchant_data.category)) {
    return false;
  }
  
  // Check business hours for certain categories
  if (auth.merchant_data.category === 'restaurants') {
    const businessHours = isBusinessHours();
    return businessHours;
  }
  
  return true;
}

Expense Management Integration

// Create cards for expense categories
const travelCard = await stripe.issuing.cards.create({
  cardholder: 'ich_employee_123',
  currency: 'usd',
  type: 'virtual',
  spending_controls: {
    allowed_categories: [
      'airlines',
      'car_rental',
      'lodging',
      'restaurants'
    ],
    spending_limits: [{
      amount: 200000, // $2,000 monthly travel budget
      interval: 'monthly'
    }]
  },
  metadata: {
    expense_category: 'travel',
    employee_id: 'emp_123'
  }
});

// Monitor transactions for expense reporting
const transactions = await stripe.issuing.transactions.list({
  card: travelCard.id
});

for (const transaction of transactions.data) {
  await createExpenseEntry({
    employee_id: transaction.metadata?.employee_id,
    category: transaction.merchant_data.category,
    amount: transaction.amount,
    merchant: transaction.merchant_data.name,
    date: new Date(transaction.created * 1000)
  });
}

Type Definitions

interface Address {
  /** City/District/Suburb/Town/Village */
  city: string | null;
  /** 2-letter country code */
  country: string | null;
  /** Address line 1 (Street address/PO Box/Company name) */
  line1: string | null;
  /** Address line 2 (Apartment/Suite/Unit/Building) */
  line2: string | null;
  /** ZIP or postal code */
  postal_code: string | null;
  /** State/County/Province/Region */
  state: string | null;
}

interface FlightDetails {
  /** The time that the flight departed */
  departure_at: number | null;
  /** The name of the passenger */
  passenger_name: string | null;
  /** Whether the ticket is refundable */
  refundable: boolean | null;
  /** The legs of the trip */
  segments: Array<{
    /** The three-letter IATA airport code of the flight's destination */
    arrival_airport_code: string | null;
    /** The airline carrier code */
    carrier: string | null;
    /** The three-letter IATA airport code that the flight departed from */
    departure_airport_code: string | null;
    /** The flight number */
    flight_number: string | null;
    /** The flight's service class */
    service_class: string | null;
    /** Whether a stopover is allowed on this flight */
    stopover_allowed: boolean | null;
  }> | null;
  /** The travel agency that issued the ticket */
  travel_agency: string | null;
}

interface FuelDetails {
  /** Conexxus Payment System Product Code identifying the primary fuel product purchased */
  industry_product_code: string | null;
  /** The quantity of units of fuel that was dispensed, represented as a decimal string with at most 12 decimal places */
  quantity_decimal: string | null;
  /** The type of fuel that was purchased. One of 'diesel', 'unleaded_plus', 'unleaded_regular', 'unleaded_super', or 'other' */
  type: string;
  /** The units for quantity_decimal. One of 'charging_minute', 'imperial_gallon', 'kilogram', 'kilowatt_hour', 'liter', 'pound', 'us_gallon', or 'other' */
  unit: string;
  /** The cost in cents per each unit of fuel, represented as a decimal string with at most 12 decimal places */
  unit_cost_decimal: string;
}

interface LodgingDetails {
  /** The time of checking into the lodging */
  check_in_at: number | null;
  /** The number of nights stayed at the lodging */
  nights: number | null;
}

interface ReceiptDetails {
  /** The description of the item. The maximum length of this field is 26 characters */
  description: string | null;
  /** The quantity of the item */
  quantity: number | null;
  /** The total for this line item in cents */
  total: number | null;
  /** The unit cost of the item in cents */
  unit_cost: number | null;
}

Stripe Issuing provides a complete card issuing platform with sophisticated controls, real-time monitoring, and comprehensive dispute management capabilities for modern corporate card programs.

Install with Tessl CLI

npx tessl i tessl/npm-stripe

docs

billing.md

checkout.md

configuration.md

core-resources.md

identity.md

index.md

issuing.md

radar.md

subscriptions.md

tax.md

terminal.md

treasury.md

webhooks.md

tile.json