Workflow Name: API Integration Builder
Category: Development
Description: Generate code to integrate with external APIs
API Name: Stripe
Language: Node.js
Endpoints: charges, customers
Step: 1 of 2: generate_code
This output provides Node.js code for integrating with the Stripe API, focusing on the customers and charges (specifically, PaymentIntents as the recommended modern approach) endpoints. The code is structured into a reusable module, stripeService.js, which encapsulates Stripe API interactions. It includes functions for common operations like creating, retrieving, updating, and listing resources, along with basic error handling and best practices for API key management.
Before using the generated code, ensure the following are in place:
If you don't have Node.js installed, download it from [nodejs.org](https://nodejs.org/). npm (Node Package Manager) is included with Node.js.
Navigate to your project directory in the terminal and initialize a new Node.js project:
* `stripe`: The official Stripe Node.js client library. * `dotenv`: For securely loading environment variables from a `.env` file. ### 4. Obtain Your Stripe API Keys You will need your **Stripe Secret Key**. This key should never be exposed in client-side code or committed to version control. * Go to your [Stripe Dashboard](https://dashboard.stripe.com/apikeys). * Copy your "Secret key" (starts with `sk_live_...` for live mode or `sk_test_...` for test mode). ### 5. Configure Environment Variables Create a file named `.env` in the root of your project directory and add your Stripe Secret Key:
* Recommendation: For new payment flows, always use PaymentIntents. They are designed to handle complex payment lifecycles, including strong customer authentication (SCA) requirements like 3D Secure, and provide better idempotency and state management.
* Charges API is simpler but less flexible and does not inherently support dynamic authentication flows. It's suitable for single-step charges where authentication is not a concern or for retrieving historical charge data.
* Never hardcode your Stripe Secret Key directly in your code. Always use environment variables (e.g., via dotenv in Node.js) or a secure configuration management system.
* Your Publishable Key (pk_live_... or pk_test_...) is safe to include in client-side code (e.g., in your frontend JavaScript using Stripe.js).
* The provided code includes basic try...catch blocks. In a production application, you should implement more robust error handling, including logging, specific error types from Stripe (e.g., StripeCardError), and user-friendly error messages.
* Consider implementing retries for transient network errors.
* Stripe supports idempotency keys to prevent duplicate API requests (e.g., if a network error occurs and you retry a createPaymentIntent call). While not explicitly shown in this basic example, for critical operations like creating charges or PaymentIntents, it's highly recommended to generate and pass a unique idempotency key with each request.
* Example: await stripe.paymentIntents.create(data, { idempotencyKey: 'your_unique_key_here' });
* For real-time updates on payment status, refunds, subscriptions, etc., implement Stripe Webhooks. Your server receives notifications from Stripe when events occur (e.g., payment_intent.succeeded, charge.refunded). This is crucial for maintaining accurate state in your application.
* This backend code handles server-side API calls. For collecting sensitive payment information (card details), you must use Stripe.js on your frontend. Stripe.js tokenizes card details directly from the user's browser, ensuring PCI compliance and preventing sensitive data from touching your server.
* The client_secret returned by createPaymentIntent is used by Stripe.js on the frontend to confirm the payment.
* When listing resources (e.g., listCustomers, listPaymentIntents), Stripe API responses are paginated. The provided list functions retrieve only the first page. For large datasets, implement proper pagination logic using limit, starting_after, and ending_before parameters, or use the autoPagingIterator available in the Stripe Node.js library.
stripeService.js module into your existing Node.js application (e.g., an Express.js server).* Set up your frontend to use Stripe.js for securely collecting payment details and confirming PaymentIntents.
* Send the client_secret from your backend's createPaymentIntent response to your frontend.
* Configure webhooks in your Stripe Dashboard.
* Create a webhook endpoint in your Node.js application to listen for and process Stripe events.
* Thoroughly test all API interactions using Stripe's test cards and test modes.
* Simulate various scenarios: successful payments, declined cards, 3D Secure challenges, refunds, etc.
* Implement additional Stripe features as needed (e.g., Refunds, Subscriptions, Connect, Payouts).
* Add more specific validation and error handling logic tailored to your application's requirements.
PantheraHive Workflow Execution: API Integration Builder
This document provides a comprehensive guide and code examples for integrating with the Stripe API using Node.js, specifically focusing on the charges and customers endpoints.
This output provides a ready-to-use Node.js project structure and code snippets for interacting with the Stripe API. The primary goal is to enable your application to manage customer information and process payments (charges) effectively.
Key Features:
customers (Create, Retrieve, Update, Delete, List).charges (Create, Retrieve, List).To get started, create a new Node.js project and install the necessary dependencies.
# Create a new directory for your project
mkdir stripe-integration-project
cd stripe-integration-project
# Initialize a new Node.js project
npm init -y
You'll need the stripe SDK for Node.js, dotenv for environment variable management, and optionally express if you plan to build a web server around this integration.
npm install stripe dotenv express
A clean project structure helps manage your code. Here’s a recommended layout:
stripe-integration-project/
├── .env # Environment variables (Stripe secret key)
├── package.json
├── package-lock.json
├── index.js # Main application entry point (example usage)
└── src/
├── config/
│ └── stripe.js # Stripe client initialization
└── services/
└── stripeService.js # Core Stripe API interaction logic
Security is paramount. Never hardcode your Stripe secret keys directly in your code. Use environment variables.
pk_test_ or pk_live_) and Secret key (starts with sk_test_ or sk_live_)..env FileIn the root of your project (stripe-integration-project/.env), create a .env file and add your Stripe secret key:
STRIPE_SECRET_KEY=sk_test_YOUR_STRIPE_SECRET_KEY
Important: Add .env to your .gitignore file to prevent it from being committed to version control.
# .gitignore
.env
node_modules/
Initialize the Stripe client using your secret key.
src/config/stripe.js
// src/config/stripe.js
require('dotenv').config(); // Load environment variables
if (!process.env.STRIPE_SECRET_KEY) {
console.error("Error: STRIPE_SECRET_KEY is not set in environment variables.");
process.exit(1); // Exit if critical env var is missing
}
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
module.exports = stripe;
This section provides the core logic for interacting with the charges and customers endpoints.
src/services/stripeService.jsThis module will encapsulate all Stripe API calls.
// src/services/stripeService.js
const stripe = require('../config/stripe');
/**
* Handles common Stripe API errors.
* @param {Error} error - The error object from Stripe.
* @returns {object} An object containing error details.
*/
const handleStripeError = (error) => {
if (error.type === 'StripeCardError') {
// A declined card error
return {
success: false,
code: error.code,
message: error.message,
param: error.param,
statusCode: error.statusCode,
type: 'StripeCardError'
};
} else if (error.type === 'StripeRateLimitError') {
// Too many requests made to the API too quickly
return {
success: false,
code: error.code,
message: 'Too many requests. Please try again later.',
statusCode: error.statusCode,
type: 'StripeRateLimitError'
};
} else if (error.type === 'StripeInvalidRequestError') {
// Invalid parameters were supplied to Stripe's API
return {
success: false,
code: error.code,
message: error.message,
param: error.param,
statusCode: error.statusCode,
type: 'StripeInvalidRequestError'
};
} else if (error.type === 'StripeAPIError') {
// An error occurred internally with Stripe's API
return {
success: false,
code: error.code,
message: 'Stripe API error. Please try again later.',
statusCode: error.statusCode,
type: 'StripeAPIError'
};
} else if (error.type === 'StripeAuthenticationError') {
// You probably used an incorrect API key
return {
success: false,
code: error.code,
message: 'Authentication with Stripe failed. Check your API key.',
statusCode: error.statusCode,
type: 'StripeAuthenticationError'
};
} else {
// Generic error
return {
success: false,
code: 'UNKNOWN_ERROR',
message: error.message || 'An unexpected error occurred.',
statusCode: error.statusCode || 500,
type: 'GenericError'
};
}
};
// --- Customer Operations ---
/**
* Creates a new customer in Stripe.
* @param {object} customerData - Customer details (e.g., email, name, description).
* @returns {Promise<object>} The created customer object or an error.
*/
const createCustomer = async (customerData) => {
try {
const customer = await stripe.customers.create(customerData);
return { success: true, customer };
} catch (error) {
console.error('Error creating customer:', error);
return handleStripeError(error);
}
};
/**
* Retrieves a customer by ID.
* @param {string} customerId - The ID of the customer to retrieve.
* @returns {Promise<object>} The customer object or an error.
*/
const retrieveCustomer = async (customerId) => {
try {
const customer = await stripe.customers.retrieve(customerId);
if (!customer || customer.deleted) {
return { success: false, message: 'Customer not found or deleted.', statusCode: 404 };
}
return { success: true, customer };
} catch (error) {
console.error(`Error retrieving customer ${customerId}:`, error);
return handleStripeError(error);
}
};
/**
* Updates an existing customer.
* @param {string} customerId - The ID of the customer to update.
* @param {object} updates - An object containing fields to update.
* @returns {Promise<object>} The updated customer object or an error.
*/
const updateCustomer = async (customerId, updates) => {
try {
const customer = await stripe.customers.update(customerId, updates);
return { success: true, customer };
} catch (error) {
console.error(`Error updating customer ${customerId}:`, error);
return handleStripeError(error);
}
};
/**
* Deletes a customer.
* @param {string} customerId - The ID of the customer to delete.
* @returns {Promise<object>} Confirmation of deletion or an error.
*/
const deleteCustomer = async (customerId) => {
try {
const confirmation = await stripe.customers.del(customerId);
return { success: true, confirmation };
} catch (error) {
console.error(`Error deleting customer ${customerId}:`, error);
return handleStripeError(error);
}
};
/**
* Lists customers.
* @param {object} [options] - Options for listing customers (e.g., limit, starting_after).
* @returns {Promise<object>} A list of customer objects or an error.
*/
const listCustomers = async (options = {}) => {
try {
const customers = await stripe.customers.list(options);
return { success: true, customers: customers.data, has_more: customers.has_more };
} catch (error) {
console.error('Error listing customers:', error);
return handleStripeError(error);
}
};
// --- Charge Operations ---
/**
* Creates a new charge. This typically happens after a payment method (e.g., card token or PaymentMethod ID)
* has been collected on the client-side.
* @param {object} chargeData - Details for the charge (e.g., amount, currency, source/payment_method, customer, description).
* @returns {Promise<object>} The created charge object or an error.
*/
const createCharge = async (chargeData) => {
try {
const charge = await stripe.charges.create(chargeData);
return { success: true, charge };
} catch (error) {
console.error('Error creating charge:', error);
return handleStripeError(error);
}
};
/**
* Retrieves a charge by ID.
* @param {string} chargeId - The ID of the charge to retrieve.
* @returns {Promise<object>} The charge object or an error.
*/
const retrieveCharge = async (chargeId) => {
try {
const charge = await stripe.charges.retrieve(chargeId);
if (!charge) {
return { success: false, message: 'Charge not found.', statusCode: 404 };
}
return { success: true, charge };
} catch (error) {
console.error(`Error retrieving charge ${chargeId}:`, error);
return handleStripeError(error);
}
};
/**
* Lists charges.
* @param {object} [options] - Options for listing charges (e.g., limit, starting_after, customer).
* @returns {Promise<object>} A list of charge objects or an error.
*/
const listCharges = async (options = {}) => {
try {
const charges = await stripe.charges.list(options);
return { success: true, charges: charges.data, has_more: charges.has_more };
} catch (error) {
console.error('Error listing charges:', error);
return handleStripeError(error);
}
};
module.exports = {
createCustomer,
retrieveCustomer,
updateCustomer,
deleteCustomer,
listCustomers,
createCharge,
retrieveCharge,
listCharges,
};
index.js (Example Usage)This file demonstrates how to use the stripeService functions.
// index.js
const stripeService = require('./src/services/stripeService');
const runExamples = async () => {
console.log('--- Stripe API Integration Examples ---');
// --- Customer Examples ---
console.log('\n--- Customer Operations ---');
// 1. Create a Customer
console.log('Creating a new customer...');
const newCustomer = await stripeService.createCustomer({
email: `test-customer-${Date.now()}@example.com`,
name: 'Jane Doe',
description: 'Test customer for API integration',
phone: '+15551234567'
});
if (newCustomer.success) {
console.log('Customer created successfully:', newCustomer.customer.id, newCustomer.customer.email);
const customerId = newCustomer.customer.id;
// 2. Retrieve Customer
console.log(`\nRetrieving customer ${customerId}...`);
const retrievedCustomer = await stripeService.retrieveCustomer(customerId);
if (retrievedCustomer.success) {
console.log('Customer retrieved:', retrievedCustomer.customer.name);
} else {
console.error('Failed to retrieve customer:', retrievedCustomer.message);
}
// 3. Update Customer
console.log(`\nUpdating customer ${customerId}...`);
const updatedCustomer = await stripeService.updateCustomer(customerId, {
description: 'Updated description for test customer',
metadata: {
loyalty_program: 'gold'
}
});
if (updatedCustomer.success) {
console.log('Customer updated:', updatedCustomer.customer.description, updatedCustomer.customer.metadata);
} else {
console.error('Failed to update customer:', updatedCustomer.message);
}
// 4. List Customers (e.g., retrieve the first 3 customers)
console.log('\nListing customers...');
const customerList = await stripeService.listCustomers({ limit: 3 });
if (customerList.success) {
console.log(`Listed ${customerList.customers.length} customers.`);
customerList.customers.forEach(cust => console.log(`- ${cust.id}: ${cust.email}`));
} else {
console.error('Failed to list customers:', customerList.message);
}
// --- Charge Examples (Requires a valid payment method ID or token) ---
// NOTE: For a real application, you would collect payment method details
// using Stripe Elements on the client-side and send the resulting
// `payment_method.id` or `token.id` to your server.
// For this example, we'll simulate using a test token or a PaymentMethod ID
// that could be attached to the customer.
console.log('\n--- Charge Operations ---');
// Example: Create a Payment Method and attach to customer (simulated for server-side)
// In a real scenario, this would be done on the client-side using Stripe.js
// and then sent to the server. For server-side testing, you can use test tokens.
// For actual charges, you'd typically use a PaymentMethod ID or a Source ID.
// Let's assume we have a test payment method ID from a previous client-side interaction.
// Replace 'pm_card_visa' with a valid test PaymentMethod ID or a token ID from client-side.
const testPaymentMethodId = 'pm_card_visa'; // Use a valid test PM ID from Stripe docs or your tests
// 1. Create a Charge
console.log('Creating a new charge...');
const newCharge = await stripeService.createCharge({
amount: 2000, // Amount in cents ($20.00)
currency: 'usd',
customer: customerId, // Associate charge with the created customer
payment_method: testPaymentMethodId, // Use a valid payment method ID
confirm: true, // Confirm the payment immediately
description: 'Example charge for product A',
metadata: {
order_id: 'ORDER12345'
}
});
if (newCharge.success) {
console.log('Charge created successfully:', newCharge.charge.id, newCharge.charge.status);
const chargeId = newCharge.charge.id;
// 2. Retrieve Charge
console.log(`\nRetrieving charge ${chargeId}...`);
const retrievedCharge = await stripeService.retrieveCharge(chargeId);
if (retrievedCharge.success) {
console.log('Charge retrieved:', retrievedCharge.charge.amount, retrievedCharge.charge.currency);
} else {
console.error('Failed to retrieve charge:', retrievedCharge.message);
}
// 3. List Charges (e.g., retrieve the last 2 charges for this customer)
console.log('\nListing charges...');
const chargeList = await stripeService.listCharges({ customer: customerId, limit: 2 });
if (chargeList.success) {
console.log(`Listed ${chargeList.charges.length} charges for customer ${customerId}.`);
chargeList.charges.forEach(chg => console.log(`- ${chg.id}: ${chg.amount / 100} ${chg.currency.toUpperCase()} (${chg.status})`));
} else {
console.error('Failed to list charges:', chargeList.message);
}
} else {
console.error('Failed to create charge:', newCharge.message);
// Log more details if available
if (newCharge.code) console.error('Stripe error code:', newCharge.code);
if (newCharge.param) console.error('Stripe error param:', newCharge.param);
}
// 5. Delete Customer (optional, uncomment to clean up test data)
// console.log(`\nDeleting customer ${customerId}...`);
// const deletedCustomer = await stripeService.deleteCustomer(customerId);
// if (deletedCustomer.success) {
// console.log('Customer deleted successfully:', deletedCustomer.confirmation.id);
// } else {
// console.error('Failed to delete customer:', deletedCustomer.message);
// }
} else {
console.error('Failed to create customer for example run:', newCustomer.message);
}
console.log('\n--- End of Examples ---');
};
runExamples();
.env file has STRIPE_SECRET_KEY set.
node index.js
This will execute the example operations and print the results to your console.
The stripeService.js includes a handleStripeError function to centralize error processing. Stripe's API returns specific error types (e.g., StripeCardError, StripeInvalidRequestError), which are crucial for providing meaningful feedback to users or for internal debugging.
Recommendations:
StripeRateLimitError or StripeAPIError. * Never commit .env to Git. Use .gitignore.
* Never expose your secret key to the client-side. All operations requiring the secret key must be performed on your secure backend server.
sk_test_ keys for development and testing. Stripe provides a comprehensive set of [test card numbers](https://stripe.com/docs/testing) to simulate various scenarios (success, decline, fraud, etc.).stripeService.js functions. Mock the stripe object to avoid making actual API calls during unit tests.createCharge), use idempotency keys to ensure that retrying a request due to a network error doesn't result in duplicate operations. The Stripe Node.js library automatically adds idempotency keys to requests by default, but it's good to be aware of.payment_intent.succeeded, charge.refunded, customer.subscription.created). This is crucial for handling asynchronous processes and keeping your application's state synchronized with Stripe.charges. Payment Intents handle dynamic authentication methods (like 3D Secure) and provide a more robust payment lifecycle.This output provides a solid foundation for integrating Stripe's charges and customers endpoints into your Node.js application. By following the recommended practices for security, error handling, and project structure, you can build a reliable and scalable payment integration. Remember to consult the official [Stripe API Documentation](https://stripe.com/docs/api) for the most up-to-date information and to explore advanced features.
\n