Day 19: Working with APIs And Let Claude Code Handle the Integration
Learn API integration with Claude Code in 30 minutes. Two requirements: docs URL + existing pattern. Four-step workflow. Real Resend + Stripe examples included.
Hey, it's G.
Day 19 of the Claude Code series.
API integrations used to take me half a day.
Read the docs. Find the right endpoint. Figure out the auth. Write the boilerplate. Handle all the error cases. Test it.
With Claude Code, the same integration takes 30 minutes.
Not because it magically knows every API — but because it knows how to read documentation, understands common patterns, and writes the boilerplate I used to write by hand every single time.
The Problem (API Integrations Are Tedious, Not Hard)
Here's what used to happen when I needed to integrate an API:
Step 1: Read Documentation (1-2 hours)
- Find the getting started guide
- Figure out which SDK to use
- Understand the authentication flow
- Find the endpoints I need
- Learn the response formats
Step 2: Set Up Configuration (30 minutes)
- Install the SDK
- Create the client config
- Add environment variables
- Initialize the connection
Step 3: Write Boilerplate (1-2 hours)
- Create helper functions
- Handle errors for each call
- Add TypeScript types
- Write retry logic
Step 4: Test Everything (1 hour)
- Make test calls
- Handle edge cases
- Mock the client for unit tests
Step 5: Fix All the Things That Broke (1 hour)
- Auth issues
- Wrong endpoint
- Missing error handling
- Type mismatches
Total: 4-6 hours for one API integration.
And that's if nothing goes wrong.
The Concept (Every API Integration Has the Same Five Parts)
Every API integration, regardless of which service you're connecting to, has the same structure:
1. Auth Setup
API keys, OAuth tokens, environment variables
2. Client Configuration
Initializing the SDK or fetch wrapper
3. The Actual Calls
The functions that hit the endpoints you need
4. Error Handling
What happens when calls fail
5. Type Safety
TypeScript types for the responses
Claude Code handles all five.
But it needs two things to do it well:
1. The Documentation URL
Claude Code can read API docs directly.
Give it the URL to the specific page it needs rather than asking it to figure out which docs to read.
2. Your Existing Patterns
Point it at a working integration in your project so it matches what you already have.
If you have Supabase set up, show it how you structured that before asking it to add Stripe.
The mistake most developers make:
Asking Claude Code to integrate an API without giving it either of these things.
Result: It produces something generic that works in isolation but doesn't fit your project's patterns.
The API Integration Template
Here's the template I use for every integration:
I need to integrate [API name] into this project.
Documentation: [paste the specific docs URL]
What I need it to do:
[list the specific things you need]
Existing pattern to follow:
[point to a working integration]
Setup required:
- The API key is already in .env as [ENV_VAR_NAME]
- Client config should live in /lib/[service].ts
- Helper functions should live in /utils/[service].ts
Rules:
- Follow the same pattern as /lib/supabase.ts for the client
- All API calls need proper error handling
- Add TypeScript types for all responses
- Do not hardcode any API keys
The Four-Step Integration Workflow
Step 1: Set Up the Client Config
claude
> I need to set up the Stripe client for this project.
>
> Docs: https://stripe.com/docs/api
> The secret key is in .env as STRIPE_SECRET_KEY
> The publishable key is in .env as NEXT_PUBLIC_STRIPE_KEY
>
> Create /lib/stripe.ts following the same pattern
> as /lib/supabase.ts already in this project.
> Server-side and client-side instances where needed.
Claude responds:
Creating Stripe client configuration...
File: /lib/stripe.ts
Following pattern from /lib/supabase.ts:
- Server-side client using STRIPE_SECRET_KEY
- Client-side instance using NEXT_PUBLIC_STRIPE_KEY
- Environment variable validation on initialization
- Export named instances
Created:
- stripeServer (for server-side operations)
- stripeClient (for client-side checkout)
No API keys hardcoded. All from environment variables.
Step 2: Build the Helper Functions
> Now build the helper functions in /utils/payments.ts.
>
> I need these specific things:
> - Create a checkout session for a subscription
> - Handle a successful payment webhook
> - Fetch a customer's current subscription status
> - Cancel a subscription
>
> Read the Stripe docs at https://stripe.com/docs/billing/subscriptions/overview
>
> Each function needs full error handling and TypeScript types.
Claude responds:
Reading Stripe billing docs...
Creating payment utilities in /utils/payments.ts
Functions created:
1. createCheckoutSession(priceId: string, customerId: string)
- Creates Stripe checkout session
- Returns session URL and ID
- Full error handling with typed errors
2. handleSuccessfulPayment(sessionId: string)
- Retrieves session details
- Updates user subscription in database
- Returns subscription object
3. getSubscriptionStatus(customerId: string)
- Fetches current subscription
- Returns plan tier and status
- Handles missing subscription gracefully
4. cancelSubscription(subscriptionId: string)
- Cancels subscription at period end
- Updates user to free tier
- Returns cancellation confirmation
All functions include:
- TypeScript types for params and returns
- Try-catch error handling
- Stripe client from /lib/stripe.ts
- Descriptive error messages
Step 3: Handle Webhooks
> I need a webhook handler at /app/api/webhooks/stripe/route.ts
>
> It should handle these events:
> - checkout.session.completed → update user subscription in Supabase
> - customer.subscription.deleted → downgrade user to free plan
>
> Read /app/api/users/route.ts for the existing API route pattern.
> Verify the Stripe webhook signature on every request.
Claude responds:
Creating webhook handler...
File: /app/api/webhooks/stripe/route.ts
Following pattern from /app/api/users/route.ts:
- NextResponse for all responses
- Consistent error format
- Try-catch wrapping
Webhook features:
- Signature verification using STRIPE_WEBHOOK_SECRET
- Event type handling with switch statement
- checkout.session.completed → updates Supabase subscription
- customer.subscription.deleted → downgrades to free
- Unknown event types logged but don't error
Security:
- Signature verified before processing
- Returns 400 for invalid signatures
- Returns 200 for unknown event types (webhook requirement)
All Supabase operations use client from /lib/supabase.ts
Step 4: Write the Tests
> Write tests for /utils/payments.ts
>
> Mock the Stripe client — no real API calls in tests
> Cover success and failure cases for each function
Claude responds:
Creating tests for payment utilities...
File: /utils/__tests__/payments.test.ts
Mocking:
- Stripe client mocked with vi.mock()
- No real API calls made
- All responses mocked
Tests written (16 total):
createCheckoutSession:
✓ creates session successfully
✓ returns session URL and ID
✓ handles Stripe API errors
✓ validates required parameters
handleSuccessfulPayment:
✓ retrieves session correctly
✓ updates Supabase subscription
✓ handles missing session
✓ handles database update failures
getSubscriptionStatus:
✓ fetches active subscription
✓ handles no subscription found
✓ handles canceled subscription
✓ handles API errors
cancelSubscription:
✓ cancels at period end
✓ updates user to free tier
✓ handles already canceled
✓ handles cancellation errors
All tests passing.
Real Integration Example (Complete Session)
Let me walk you through integrating Resend for transactional emails in 1MinThumb.
Step 1: Read the Docs First
cd ~/projects/1minthumb
claude
> Read the Resend docs at https://resend.com/docs/introduction
>
> Tell me:
> - How authentication works
> - What SDK to use
> - What the rate limits are
> - Any gotchas or things worth knowing before integrating
>
> Then we'll build the integration.
Claude responds:
Reading Resend documentation...
Authentication:
- API key authentication
- Key goes in environment variable (RESEND_API_KEY)
- Include in headers: Authorization: Bearer {api_key}
SDK:
- Official Node.js SDK available: npm install resend
- Recommended over raw fetch calls
- TypeScript support built-in
Rate Limits:
- Free tier: 100 emails/day
- Pro tier: 50,000 emails/month
- Rate limit headers included in responses
Important notes:
- Emails must be sent from verified domain
- Free tier only sends to verified email addresses
- Sandbox mode available for testing
- Webhooks available for delivery tracking
- HTML and plain text both supported
Recommended setup:
1. Install SDK
2. Create client in /lib/resend.ts
3. Build helper functions in /utils/email.ts
4. Create email templates in /emails/
Ready to proceed?
Step 2: Set Up the Client
> Perfect. Set up the Resend client in /lib/resend.ts
>
> API key is in .env as RESEND_API_KEY
> Follow the same pattern as /lib/supabase.ts
Claude responds:
Creating Resend client configuration...
File: /lib/resend.ts
Following pattern from /lib/supabase.ts:
- Environment variable validation
- Single exported client instance
- TypeScript types
Created:
export const resend = new Resend(process.env.RESEND_API_KEY)
Includes env validation:
if (!process.env.RESEND_API_KEY) {
throw new Error('RESEND_API_KEY is not set')
}
Step 3: Build Email Helpers
> Build email helper functions in /utils/email.ts
>
> I need:
> - sendWelcomeEmail(user) → sends onboarding email
> - sendPasswordReset(user, resetUrl) → password reset email
> - sendSubscriptionConfirmation(user, plan) → payment confirmed
>
> Email templates live in /emails/
> Check what templates already exist before building.
>
> Full error handling and TypeScript types on everything.
Claude responds:
Reading /emails directory...
Found existing templates:
- welcome.tsx (React Email template)
- password-reset.tsx (React Email template)
Creating email utilities in /utils/email.ts
Functions created:
1. sendWelcomeEmail(user: User)
- Renders welcome.tsx template
- Sends from [email protected]
- Subject: "Welcome to 1MinThumb"
- Returns email ID or error
2. sendPasswordReset(user: User, resetUrl: string)
- Renders password-reset.tsx template
- Includes reset URL in template
- Expires in 1 hour note
- Returns email ID or error
3. sendSubscriptionConfirmation(user: User, plan: string)
- Plain text email (no template exists yet)
- Includes plan details
- Links to billing dashboard
- Returns email ID or error
All functions include:
- TypeScript interfaces for parameters
- Try-catch error handling
- Resend client from /lib/resend.ts
- Descriptive error messages
- Email ID returned on success
Step 4: Install the SDK
> Install the Resend SDK
Claude asks for approval:
Command to run: npm install resend
This will add the Resend SDK to package.json
Proceed? (y/n)
I approve:
y
Claude installs:
Installing resend...
✓ [email protected] installed
✓ package.json updated
✓ package-lock.json updated
Step 5: Write the Tests
> /test
Claude responds:
Creating tests for email utilities...
File: /utils/__tests__/email.test.ts
Mocking:
- Resend client mocked with vi.mock()
- No real emails sent in tests
- All send operations mocked
Tests written (9 total):
sendWelcomeEmail:
✓ sends welcome email successfully
✓ returns email ID
✓ handles send failures
✓ validates user email
sendPasswordReset:
✓ sends password reset email
✓ includes reset URL in email
✓ handles send failures
sendSubscriptionConfirmation:
✓ sends confirmation email
✓ handles send failures
All tests passing.
Step 6: Review and Ship
> /review
All clear.
> /ship
Claude responds:
Pre-Commit Workflow Complete
1. REVIEW FINDINGS:
✓ No issues found
2. CONVENTION CHECK:
✓ Named exports only
✓ Environment variables not hardcoded
✓ TypeScript types on all functions
✓ Error handling present
3. SUGGESTED COMMIT MESSAGE:
add Resend email integration
Integrated Resend for transactional emails.
Created client config, three email helper functions,
and comprehensive tests. Ready for production.
Files created:
- /lib/resend.ts
- /utils/email.ts
- /utils/__tests__/email.test.ts
4. FOLLOW-UP TASKS:
- Add subscription confirmation email template
- Set up Resend webhook for delivery tracking
- Add retry logic for failed sends
Full email integration. One session. 25 minutes.
Advanced Integration Patterns
Pattern 1: Read Docs Before Building
For unfamiliar APIs, always start here:
> Before we start building, read the [API name] docs at [URL]
>
> Tell me:
> - How authentication works
> - What the rate limits are
> - What the main endpoints we'll need are
> - Any gotchas or things worth knowing before integrating
>
> Then we'll build the integration.
This saves hours of trial and error.
Pattern 2: Match Existing Patterns
Always point to a working integration:
> Set up the [new service] client in /lib/[service].ts
>
> Follow the same pattern as /lib/supabase.ts:
> - Environment variable validation
> - Single exported instance
> - TypeScript types
Consistency across integrations makes your codebase easier to maintain.
Pattern 3: Debug Broken Integrations
When something's not working:
> The Stripe webhook is failing with this error:
> [paste error]
>
> Read /app/api/webhooks/stripe/route.ts and
> https://stripe.com/docs/webhooks/signatures
>
> Find out why the signature verification is failing.
Claude traces the issue by reading both your code and the docs.
Pattern 4: Add Features to Existing Integrations
When you need to extend an integration:
> Look at /utils/payments.ts
>
> I need to add a new function: upgradeSubscription(userId, newPlan)
>
> Read the Stripe docs on subscription updates
> Follow the same pattern as the existing functions
> Include full error handling and types
Why This Matters
API integrations are one of the highest time-cost tasks in any project.
Not because they're hard — because they're tedious.
- Reading docs
- Writing boilerplate
- Handling all the error cases
- Writing tests
- Debugging auth issues
Claude Code handles the tedious parts so you can focus on the business logic that actually matters to your product.
Every integration that used to take half a day now takes 30 minutes.
Common Integration Mistakes
❌ Mistake 1: No Documentation URL
> Integrate Stripe into this project
Problem: Claude doesn't know which docs to read. You get generic code.
Fix: Always include the specific docs URL.
❌ Mistake 2: No Existing Pattern
> Set up Stripe client
Problem: Claude creates its own structure that doesn't match your project.
Fix: Point to an existing integration to match.
❌ Mistake 3: Not Reading Docs First
Starting to build without understanding the API.
Problem: You hit gotchas you could have avoided.
Fix: Always ask Claude to read and summarize docs first.
❌ Mistake 4: Hardcoded API Keys
Not specifying environment variable requirements.
Problem: Keys end up in code instead of .env.
Fix: Always specify where keys should live.
❌ Mistake 5: No Tests with Mocked Client
Testing against real API.
Problem: Tests are slow, cost money, and can fail due to network.
Fix: Always mock the API client in tests.
My Raw Notes (Unfiltered)
The "read the docs first" prompt is the one that changed my integration workflow the most.
Used to just dive in and figure it out as I went. Asking Claude to summarize the docs before touching code means I know the gotchas before hitting them.
Resend integration for 1MinThumb took me maybe 25 minutes using this workflow.
Stripe took about 45 minutes including the webhook handler and tests.
The pattern matching instruction is important — without pointing at an existing integration Claude produces something that works but doesn't fit the project.
Always mock the API client in tests — never make real calls.
Tomorrow (Day 20 Preview)
Topic: Multi-File Workflows — how to handle tasks that touch 5+ files at once without losing context or making a mess.
What I'm testing: Can Claude Code maintain context across complex changes? How do you guide it through large refactors or feature builds that span many files?
Following This Series
Phase 3 (Days 15-21): Vibe Coding ⬅️ You are here
So far in Phase 3:
- Day 14: Vibe coding mindset
- Day 15: Feature-first workflow
- Day 16: Debugging with Claude Code
- Day 17: Refactoring with Claude Code
- Day 18: Writing tests with Claude Code
- Day 19: Working with APIs (today)
- Day 20: Multi-file workflows (tomorrow)
G
P.S. - Two things Claude needs for API integrations: documentation URL + existing pattern to follow. Without these you get generic code that doesn't fit your project.
P.P.S. - Always ask Claude to read and summarize docs before building. "How does auth work? Rate limits? Gotchas?" Know the issues before you hit them.
P.P.P.S. - Mock the API client in tests. Never make real API calls. Fast tests, no costs, no network failures.