How to Integrate with Stripe API: A Step-by-Step Guide for Developers
March 10, 2026
A Stripe API integration lets your product process payments, manage subscriptions, create invoices, issue refunds, and synchronize billing data with Stripe accounts.
For SaaS companies selling into ecommerce, marketplaces, or subscription businesses, Stripe is often the financial backbone of the product.
Typical integrations include:
- Creating payments and PaymentIntents
- Managing customers and subscriptions
- Generating invoices
- Handling refunds
- Synchronizing billing data
- Listening to payment events via webhooks
But a production-grade Stripe integration involves more than sending a payment request. You need to design for idempotency, retries, pagination, webhook reliability, and multi-account platforms like Stripe Connect.
This guide covers:
- How to integrate directly with the Stripe API
- The operational complexity you will own
- How to integrate Stripe using Unified's Payment and Accounting APIs
- When to build direct vs use an integration layer
Direct Stripe API integration
Step 1: Understand the Stripe API model
Stripe provides a REST API with resource-oriented endpoints.
All endpoints are rooted under:
https://api.stripe.com
Requests use standard HTTP methods:
GET
POST
PUT
DELETE
Requests typically send form-encoded bodies, while responses are always JSON.
Stripe's documentation explains that each API request operates on a single object, meaning the API does not support bulk updates.
Stripe API reference: https://docs.stripe.com/api
Step 2: Authenticate using API keys
Stripe authenticates API requests using API keys.
Keys are generated in the Stripe dashboard and come in several types:
| Key Type | Prefix | Usage |
|---|---|---|
| Publishable | pk_test / pk_live | client-side use |
| Secret | sk_test / sk_live | server-side API calls |
| Restricted | rk_ | limited permissions |
Example authenticated request:
curl https://api.stripe.com/v1/customers \
-u sk_test_...:
Important security practices:
- Never expose secret keys in client-side code
- Always store keys in environment variables
- Only make requests over HTTPS
Stripe authentication docs: https://docs.stripe.com/api/authentication
Step 3: Use idempotency for safe retries
Stripe supports idempotent requests to prevent duplicate operations when retries occur.
You supply an Idempotency-Key header when creating or updating objects.
Example:
curl https://api.stripe.com/v1/customers \
-H "Idempotency-Key: 3f41c9c3-3e55-4d78-a7c8" \
-u sk_test_... \
-d description="Example customer"
Stripe stores the result for that key for 24 hours, returning the same result if the request is retried.
Stripe idempotency docs: https://docs.stripe.com/api/idempotent_requests
Core Stripe operations
Stripe integrations typically revolve around several core resources.
Customers
Customers store billing and identity information for a user.
Create customer
POST /v1/customers
Common parameters:
- name
- phone
- metadata
Example:
curl https://api.stripe.com/v1/customers \
-u sk_test_... \
-d name="Jenny Rosen" \
-d email="jenny@example.com"
Stripe customers API: https://docs.stripe.com/api/customers
PaymentIntents
Stripe recommends using PaymentIntents instead of creating charges directly.
A PaymentIntent manages the full payment lifecycle.
Create payment intent
POST /v1/payment_intents
Required fields:
amount
currency
Common optional parameters:
customer
automatic_payment_methods[enabled]
payment_method
confirm
Example:
curl https://api.stripe.com/v1/payment_intents \
-u sk_test_... \
-d amount=2000 \
-d currency=usd \
-d automatic_payment_methods[enabled]=true
Stripe PaymentIntents docs: https://docs.stripe.com/api/payment_intents
Charges
The Charge object represents a completed payment.
Modern integrations typically do not create charges directly, because charges are generated automatically by PaymentIntents.
Retrieve charge:
GET /v1/charges/{charge_id}
Stripe charges docs: https://docs.stripe.com/api/charges
Invoices
Invoices allow billing customers manually or through subscriptions.
Create invoice
POST /v1/invoices
Key parameters:
customer
collection_method
due_date
auto_advance
Example:
curl https://api.stripe.com/v1/invoices \
-u sk_test_... \
-d customer=cus_123
Stripe invoices docs: https://docs.stripe.com/api/invoices
Subscriptions
Subscriptions power recurring billing.
Create subscription
POST /v1/subscriptions
Required parameters:
customer
items[0][price]
Example:
curl https://api.stripe.com/v1/subscriptions \
-u sk_test_... \
-d customer=cus_123 \
-d items[0][price]=price_monthly
Stripe subscriptions docs: https://docs.stripe.com/api/subscriptions
Refunds
Refunds return funds from a charge or PaymentIntent.
Create refund
POST /v1/refunds
Example:
curl https://api.stripe.com/v1/refunds \
-u sk_test_... \
-d payment_intent=pi_123
Stripe refunds docs: https://docs.stripe.com/api/refunds
Products and prices
Stripe separates products from prices.
Products describe what is sold.
Prices define billing amount and frequency.
Create product:
POST /v1/products
Create price:
POST /v1/prices
Stripe product docs
https://docs.stripe.com/api/products
Stripe price docs
https://docs.stripe.com/api/prices
Stripe pagination
Stripe uses cursor-based pagination.
List endpoints accept:
limit
starting_after
ending_before
Example:
GET /v1/customers?limit=100
The response includes:
data
has_more
url
Stripe pagination docs
https://docs.stripe.com/api/pagination
Stripe search API
Stripe supports search endpoints for some objects.
Example:
GET /v1/customers/search
Query example:
email:'@example.com'
Important note:
Stripe search is eventually consistent, so it should not be used for read-after-write workflows.
Stripe search docs
https://docs.stripe.com/search
Stripe webhooks
Stripe webhooks notify your system when events occur.
Example events:
payment_intent.succeeded
invoice.paid
charge.refunded
customer.subscription.created
Webhook payloads contain:
id
type
created
data.object
Security requirements:
- Verify signatures using the
Stripe-Signatureheader - Use HTTPS endpoints
- Treat events as idempotent
Stripe webhook docs
https://docs.stripe.com/webhooks
Stripe Connect for SaaS platforms
Stripe Connect enables platforms to process payments for multiple businesses.
Platforms create connected accounts, identified by:
acct_xxxxx
To act on behalf of a connected account, include:
Stripe-Account: acct_xxxxx
Example:
curl https://api.stripe.com/v1/payment_intents \
-H "Stripe-Account: acct_123"
Stripe Connect docs
https://docs.stripe.com/connect
Where Stripe integrations become operationally complex
Direct Stripe integrations require handling:
- payment state machines
- idempotency and retries
- webhook ordering and duplication
- subscription lifecycle management
- pagination across large datasets
- multi-account routing (Stripe Connect)
- API version upgrades
- billing reconciliation
For a single billing integration this is manageable.
For multi-tenant SaaS products, this becomes real integration infrastructure.
Integrating Stripe via Unified
Unified normalizes Stripe into multiple API categories.
Stripe spans:
Payment
Accounting
Commerce
Authentication
Passthrough
Step 1: Configure OAuth redirect
When registering Stripe with Unified, set the OAuth callback to:
https://api.unified.to/oauth/code
EU region variant:
https://api-eu.unified.to/oauth/code
Unified manages the OAuth handshake and returns a connection_id used in API requests.
Step 2: Use Unified normalized objects
Unified maps Stripe resources to normalized objects.
Supported Stripe objects include:
| Unified Object | Stripe Resource |
|---|---|
| payment | PaymentIntent / Charge |
| payout | Payout |
| refund | Refund |
| subscription | Subscription |
| accounting_contact | Customer |
| accounting_invoice | Invoice |
| commerce_item | Product |
| commerce_itemvariant | Price |
Unified Stripe object coverage
Payment
Methods
list
get
update
remove
List parameters
limit
offset
contact_id
updated_gte
Readable fields
id
contact_id
currency
payment_method
reference
total_amount
invoice_id
created_at
updated_at
Webhooks
Virtual
Native
Payout
Methods
list
get
Readable fields
id
status
currency
total_amount
created_at
updated_at
Webhooks
Virtual
Native
Refund
Methods
list
get
Readable fields
id
payment_id
currency
status
total_amount
created_at
updated_at
Webhooks
Virtual
Native
Subscription
Methods
list
get
Readable fields
id
status
interval
interval_unit
invoice_id
currency
current_period_start_at
current_period_end_at
Webhooks
Virtual
Native
Unified API examples
List customers:
GET /ticketing/{connection_id}/customer
Create customer:
POST /ticketing/{connection_id}/customer
List payments:
GET /payment/{connection_id}/payment
Create payment:
POST /payment/{connection_id}/payment
List invoices:
GET /accounting/{connection_id}/invoice
Create invoice:
POST /accounting/{connection_id}/invoice
Unified webhooks
Unified supports two webhook types.
Native webhooks
Forward events directly from Stripe.
Examples:
payment_intent.succeeded
invoice.paid
charge.refunded
customer.subscription.updated
Virtual webhooks
When providers lack native webhook support, Unified polls for changes and emits events.
Webhook payload includes:
data
webhook metadata
nonce
sig256
type
Possible types:
INITIAL-PARTIAL
INITIAL-COMPLETE
VIRTUAL
NATIVE
Unified passthrough
When Stripe features are not normalized, use passthrough.
Supported methods:
GET
POST
PUT
DELETE
Passthrough forwards the request to the Stripe API using the existing connection authentication.
Use cases:
- creating refunds with custom options
- managing Stripe products or prices
- calling beta Stripe APIs
Direct vs Unified: when to choose each
Build directly with Stripe if
- Stripe is a core product feature
- you need full control over PaymentIntent flows
- you rely heavily on Stripe Connect
- you need advanced billing features
Use Unified if
- Stripe is one of several payment providers
- you want normalized billing objects
- you want webhook handling abstracted
- you want to reduce integration maintenance
Final thoughts
Stripe is one of the most powerful payment APIs available.
But a production integration involves much more than sending a payment request.
The real complexity appears in:
- idempotent request handling
- webhook reliability
- subscription lifecycle management
- multi-account routing
- API versioning
- large-scale billing operations
Design your Stripe integration around PaymentIntents, webhooks, and idempotency from day one.
If Stripe is one of many billing integrations your product must support, a normalized integration layer can significantly reduce engineering overhead.