Web Development

API Integration for Websites 2026: CRM, Payment, Form, Calendar & Analytics Connections

By Reviewed by Hawrry Bhattarai
July 22, 2026 18 min read
Contents
TL;DR — the short answer

Complete guide to website API integrations in 2026 — CRM, payment, calendar, analytics, and form connections with REST API patterns, OAuth, and webhook handling.

16 min read · Web Development · Last updated July 2026

Quick answer: API integrations connect your website to business tools — turning it from a brochure into an automation hub. The most valuable connections are: form → CRM (never lose a lead), payment API (Stripe), calendar booking (Calendly/Cal.com), and GA4 Data API (custom dashboards). This guide shows you how to build each.

Introduction

A website without integrations is a brochure. A website with integrations is a business system.

When a contact form submission automatically creates a deal in your CRM, triggers a welcome email from your marketing platform, and sends a Slack notification to your sales team — that’s integration ROI. When a payment page creates a subscription in Stripe, provisions access in your app, and triggers an onboarding sequence in your email platform — that’s a connected business.

The gap between “we have a website” and “our website drives business process” is almost entirely an integration gap. This guide shows you how to close it.

What you’ll learn:
– REST API fundamentals that apply across every integration
– The 5 most valuable integrations for business websites
– Authentication patterns (API keys vs. OAuth 2.0)
– Webhook handling with retry logic and security verification
– Error handling and security best practices


Table of Contents

  1. Why API Integrations Matter
  2. REST API Fundamentals
  3. Authentication Patterns: API Keys vs. OAuth 2.0
  4. CRM Integrations: HubSpot and Salesforce
  5. Payment APIs: Stripe
  6. Form → CRM Workflows
  7. Calendar APIs: Calendly and Google Calendar
  8. Analytics APIs: GA4 Data API
  9. Webhooks vs. Polling
  10. Error Handling and Security
  11. Interactive Tools
  12. FAQ

1. Why API Integrations Matter

The average business uses 130+ SaaS tools (Okta Business at Work report, 2024). Without integrations, data moves between these tools manually — copy-pasting, re-entering, and duplicating. With integrations, data flows automatically, processes trigger in real time, and your team focuses on decisions instead of data entry.

The ROI of integration:

Manual Process Integrated Process Time Saved
Sales rep manually creates CRM contact from form Form → CRM API: automatic on submit 3-5 min per lead
Finance checks Stripe dashboard daily for new payments Stripe webhook → Slack/email: instant 10+ min daily
Admin manually schedules discovery calls Calendly embed → automatic booking 15 min per booking
Marketing pulls GA4 report monthly GA4 Data API → automated dashboard 2-3 hours/month

For a business with 50 leads/month, the CRM integration alone saves 2.5-4 hours of manual work monthly. That’s before counting errors from manual data entry.


2. REST API Fundamentals

REST (Representational State Transfer) is the architectural style used by the vast majority of modern APIs. Understanding the fundamentals lets you work with any API you encounter.

HTTP Methods

Method Purpose Example
GET Retrieve data GET /contacts — list all contacts
POST Create new resource POST /contacts — create a contact
PUT Replace a resource PUT /contacts/123 — replace contact 123
PATCH Update part of a resource PATCH /contacts/123 — update specific fields
DELETE Delete a resource DELETE /contacts/123 — delete contact 123

Anatomy of an API Request

// Example: Create a HubSpot contact via REST API
const response = await fetch('https://api.hubapi.com/crm/v3/objects/contacts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`
  },
  body: JSON.stringify({
    properties: {
      email: 'alex@example.com',
      firstname: 'Alex',
      lastname: 'Smith',
      phone: '+61400000000',
      hs_lead_status: 'NEW'
    }
  })
});

if (!response.ok) {
  const error = await response.json();
  throw new Error(`HubSpot API error: ${error.message}`);
}

const contact = await response.json();
console.log('Created contact:', contact.id);

JSON: The Universal Format

Almost all REST APIs send and receive JSON (JavaScript Object Notation). A JSON payload is a key-value structure:

{
  "email": "alex@example.com",
  "firstname": "Alex",
  "lastname": "Smith",
  "company": "Example Pty Ltd",
  "tags": ["web-form", "july-2026"],
  "metadata": {
    "source_page": "/contact",
    "utm_source": "google"
  }
}

HTTP Status Codes

Code Meaning Action
200 OK Success — data returned Process response
201 Created Success — resource created Store ID from response
400 Bad Request Malformed request Check your JSON payload
401 Unauthorized Invalid/missing auth Check API key/token
403 Forbidden Valid auth, no permission Check API scope
404 Not Found Resource doesn’t exist Check the ID
429 Too Many Requests Rate limited Implement backoff
500 Server Error API server problem Retry with backoff

3. Authentication Patterns: API Keys vs. OAuth 2.0

API Keys

The simplest authentication pattern. A static string that identifies and authorises your application.

// API Key in Authorization header (most common)
headers: {
  'Authorization': `Bearer sk_live_abc123xyz`
}

// API Key as query parameter (older pattern, less secure)
const url = `https://api.example.com/data?api_key=abc123xyz`;

When to use: Server-side integrations where your code runs on your own server (Node.js backend, serverless functions). API keys should never appear in frontend JavaScript — anyone can view your page source and steal the key.

Storing API keys securely:

# Environment variables — never commit to git
HUBSPOT_ACCESS_TOKEN=pat-na1-abc123...
STRIPE_SECRET_KEY=sk_live_abc123...
GOOGLE_CLIENT_SECRET=GOCSPX-abc123...
// Access in Node.js
const hubspotToken = process.env.HUBSPOT_ACCESS_TOKEN;

// Never hardcode:
const hubspotToken = 'pat-na1-abc123...'; // ❌ DO NOT DO THIS

OAuth 2.0

OAuth 2.0 is used when your application needs to access data on behalf of a user — for example, connecting your website to a user’s Google account to post to their calendar.

OAuth 2.0 flow (simplified):

  1. User clicks “Connect with Google”
  2. Your app redirects to Google’s authorisation endpoint with your client_id and requested scopes
  3. User approves access
  4. Google redirects back to your redirect_uri with an authorisation code
  5. Your server exchanges the code for access_token and refresh_token
  6. You use the access_token for API requests; use refresh_token to get a new access_token when it expires
// Step 5: Exchange code for tokens (server-side)
const tokenResponse = await fetch('https://oauth2.googleapis.com/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    code: req.query.code,
    client_id: process.env.GOOGLE_CLIENT_ID,
    client_secret: process.env.GOOGLE_CLIENT_SECRET,
    redirect_uri: 'https://yoursite.com/auth/callback',
    grant_type: 'authorization_code',
  })
});

const { access_token, refresh_token, expires_in } = await tokenResponse.json();

// Store tokens securely (database, not in code)
await db.storeTokens(userId, { access_token, refresh_token, expires_in });

When to use OAuth 2.0:
– Accessing user-specific data (their calendar, their email, their files)
– Third-party login (“Sign in with Google”)
– Any integration that requires the user’s permission

When to use API keys instead:
– Server-to-server integrations
– Using your own account’s data (your HubSpot CRM, your Stripe account)
– Simpler setups where OAuth overhead isn’t warranted


4. CRM Integrations: HubSpot and Salesforce

HubSpot API Integration

HubSpot’s API is well-documented and uses Bearer token authentication. Start with a Private App token (more secure than legacy API keys).

Create a HubSpot contact from a form submission:

// /api/submit-contact.js (serverless function or Express route)
export async function POST(request) {
  const body = await request.json();
  const { name, email, phone, message, source_url } = body;

  const [firstname, ...rest] = name.split(' ');
  const lastname = rest.join(' ');

  try {
    // Create contact in HubSpot
    const contactRes = await fetch(
      'https://api.hubapi.com/crm/v3/objects/contacts',
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`
        },
        body: JSON.stringify({
          properties: {
            email,
            firstname,
            lastname,
            phone,
            message,
            hs_lead_status: 'NEW',
            lead_source_url: source_url
          }
        })
      }
    );

    if (contactRes.status === 409) {
      // Contact already exists — update instead
      const existing = await getContactByEmail(email);
      await updateContact(existing.id, { phone, message });
    } else if (!contactRes.ok) {
      const err = await contactRes.json();
      throw new Error(err.message);
    }

    const contact = await contactRes.json();

    // Optionally: create a deal linked to the contact
    await createDeal(contact.id, { name: `Enquiry from ${name}` });

    return Response.json({ success: true, contactId: contact.id });

  } catch (error) {
    console.error('HubSpot error:', error);
    return Response.json({ success: false, error: error.message }, { status: 500 });
  }
}

HubSpot deal creation:

async function createDeal(contactId, { name }) {
  const dealRes = await fetch(
    'https://api.hubapi.com/crm/v3/objects/deals',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`
      },
      body: JSON.stringify({
        properties: {
          dealname: name,
          dealstage: 'appointmentscheduled',
          pipeline: 'default'
        },
        associations: [
          {
            to: { id: contactId },
            types: [{ associationCategory: 'HUBSPOT_DEFINED', associationTypeId: 3 }]
          }
        ]
      })
    }
  );
  return dealRes.json();
}

Field Mapping Best Practice

Document your field mapping before writing any code:

Form Field HubSpot Property Type
Name firstname + lastname String
Email email String (unique)
Phone phone String
Message message (custom) String
Source Page lead_source_url (custom) String
UTM Source hs_analytics_source Enum

5. Payment APIs: Stripe

Stripe is the gold standard for payment API integration. Its documentation is exceptional and its API is among the best-designed in the industry.

Stripe Checkout (Simplest Integration)

// Server: Create a Checkout Session
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export async function POST(request) {
  const { priceId, customerId } = await request.json();

  const session = await stripe.checkout.sessions.create({
    payment_method_types: ['card'],
    mode: 'subscription', // or 'payment' for one-off
    line_items: [{ price: priceId, quantity: 1 }],
    customer: customerId, // if returning customer
    success_url: `${process.env.BASE_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${process.env.BASE_URL}/pricing`,
    metadata: {
      source: 'website-pricing-page'
    }
  });

  return Response.json({ url: session.url });
}
// Client: Redirect to Stripe Checkout
async function startCheckout(priceId) {
  const response = await fetch('/api/create-checkout', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ priceId })
  });
  const { url } = await response.json();
  window.location.href = url;
}

Stripe Webhooks

Webhooks are how Stripe tells your server about events (payment succeeded, subscription cancelled, invoice paid). Never rely on the success redirect URL alone — users can close the browser before it loads.

// /api/stripe-webhook.js
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export async function POST(request) {
  const body = await request.text();
  const sig = request.headers.get('stripe-signature');

  let event;
  try {
    // Verify webhook signature (CRITICAL for security)
    event = stripe.webhooks.constructEvent(
      body,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET
    );
  } catch (err) {
    return new Response(`Webhook Error: ${err.message}`, { status: 400 });
  }

  // Handle specific events
  switch (event.type) {
    case 'checkout.session.completed':
      const session = event.data.object;
      await handleSuccessfulPayment(session);
      break;

    case 'customer.subscription.deleted':
      const subscription = event.data.object;
      await handleSubscriptionCancellation(subscription);
      break;

    case 'invoice.payment_failed':
      const invoice = event.data.object;
      await handlePaymentFailure(invoice);
      break;
  }

  // Always return 200 to acknowledge receipt
  return new Response(JSON.stringify({ received: true }), { status: 200 });
}

async function handleSuccessfulPayment(session) {
  const customerId = session.customer;
  const customerEmail = session.customer_details.email;

  // 1. Update your database
  await db.createSubscription({ customerId, email: customerEmail, status: 'active' });

  // 2. Trigger welcome email
  await sendWelcomeEmail(customerEmail);

  // 3. Notify Slack
  await notifySlack(`New subscription: ${customerEmail}`);
}

6. Form → CRM Workflows

Architecture: Direct API Call vs. Webhook

Pattern A: Direct API call from your server

Form Submit → Your Server → CRM API → Success Response → Thank You Page

Pros: Simple, synchronous, easy to debug
Cons: If CRM API is slow, form submission feels slow

Pattern B: Queue-based with webhook

Form Submit → Your Server (save to DB) → Queue → CRM API (async)

Pros: Form response is instant regardless of CRM API speed
Cons: More complex infrastructure

For most small-medium websites, Pattern A is appropriate. Pattern B is for high-volume forms or unreliable third-party APIs.

Deduplication Strategy

CRM contacts should not be duplicated. Always check if a contact exists by email before creating:

async function getOrCreateContact(email, properties) {
  // Try to find existing contact
  const searchRes = await fetch(
    `https://api.hubapi.com/crm/v3/objects/contacts/search`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`
      },
      body: JSON.stringify({
        filterGroups: [{
          filters: [{ propertyName: 'email', operator: 'EQ', value: email }]
        }],
        limit: 1
      })
    }
  );

  const searchData = await searchRes.json();

  if (searchData.results.length > 0) {
    // Update existing contact
    const existingId = searchData.results[0].id;
    await updateContact(existingId, properties);
    return { id: existingId, isNew: false };
  }

  // Create new contact
  const createRes = await createContact({ email, ...properties });
  return { id: createRes.id, isNew: true };
}

7. Calendar APIs: Calendly and Google Calendar

Calendly API

Calendly’s API allows you to embed scheduling, retrieve booking data, and set up webhooks for new bookings.

// Get available event types for your account
const eventTypes = await fetch('https://api.calendly.com/event_types', {
  headers: {
    'Authorization': `Bearer ${process.env.CALENDLY_ACCESS_TOKEN}`,
    'Content-Type': 'application/json'
  }
});

// Calendly webhook: receive when someone books
export async function POST(request) {
  const event = await request.json();

  if (event.event === 'invitee.created') {
    const booking = event.payload;
    const inviteeEmail = booking.invitee.email;
    const inviteeName = booking.invitee.name;
    const eventTime = booking.event.start_time;

    // Create CRM contact with meeting booked
    await createHubSpotContact({
      email: inviteeEmail,
      name: inviteeName,
      hs_lead_status: 'OPEN_DEAL',
      meeting_time: eventTime
    });

    // Send internal notification
    await sendSlackMessage(`New meeting booked: ${inviteeName} at ${eventTime}`);
  }

  return Response.json({ received: true });
}

Google Calendar API

For building custom booking widgets, Google Calendar API lets you check free/busy times and create events:

// Check availability for a given time range
async function checkAvailability(accessToken, calendarId, timeMin, timeMax) {
  const res = await fetch(
    `https://www.googleapis.com/calendar/v3/freeBusy`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        timeMin,
        timeMax,
        items: [{ id: calendarId }]
      })
    }
  );
  const data = await res.json();
  return data.calendars[calendarId].busy; // Array of busy time ranges
}

// Create a calendar event
async function createCalendarEvent(accessToken, calendarId, event) {
  const res = await fetch(
    `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        summary: event.title,
        description: event.description,
        start: { dateTime: event.startTime, timeZone: 'Asia/Kathmandu' },
        end: { dateTime: event.endTime, timeZone: 'Asia/Kathmandu' },
        attendees: event.attendees.map(email => ({ email })),
        conferenceData: {
          createRequest: { requestId: `meet-${Date.now()}` }
        }
      })
    }
  );
  return res.json();
}

8. Analytics APIs: GA4 Data API

The GA4 Data API lets you build custom dashboards, pull metrics into other tools, and automate reporting.

const { BetaAnalyticsDataClient } = require('@google-analytics/data');
const client = new BetaAnalyticsDataClient({
  credentials: JSON.parse(process.env.GA4_SERVICE_ACCOUNT_KEY)
});

async function getWebsiteMetrics(propertyId, startDate, endDate) {
  const [response] = await client.runReport({
    property: `properties/${propertyId}`,
    dateRanges: [{ startDate, endDate }],
    metrics: [
      { name: 'sessions' },
      { name: 'activeUsers' },
      { name: 'conversions' },
      { name: 'bounceRate' },
      { name: 'averageSessionDuration' }
    ],
    dimensions: [
      { name: 'date' },
      { name: 'sessionDefaultChannelGrouping' }
    ]
  });

  // Parse the response
  return response.rows.map(row => ({
    date: row.dimensionValues[0].value,
    channel: row.dimensionValues[1].value,
    sessions: parseInt(row.metricValues[0].value),
    users: parseInt(row.metricValues[1].value),
    conversions: parseInt(row.metricValues[2].value),
    bounceRate: parseFloat(row.metricValues[3].value),
    avgDuration: parseFloat(row.metricValues[4].value)
  }));
}

// Get top pages
async function getTopPages(propertyId, startDate, endDate, limit = 10) {
  const [response] = await client.runReport({
    property: `properties/${propertyId}`,
    dateRanges: [{ startDate, endDate }],
    metrics: [{ name: 'screenPageViews' }, { name: 'sessions' }],
    dimensions: [{ name: 'pagePath' }, { name: 'pageTitle' }],
    orderBys: [{ metric: { metricName: 'screenPageViews' }, desc: true }],
    limit
  });

  return response.rows.map(row => ({
    path: row.dimensionValues[0].value,
    title: row.dimensionValues[1].value,
    views: parseInt(row.metricValues[0].value),
    sessions: parseInt(row.metricValues[1].value)
  }));
}

9. Webhooks vs. Polling

Polling

Your server periodically requests new data from an API:

// Poll every 5 minutes for new HubSpot contacts
setInterval(async () => {
  const recentContacts = await fetch(
    'https://api.hubapi.com/crm/v3/objects/contacts?sort=-createdate&limit=10',
    { headers: { Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}` } }
  );
  const data = await recentContacts.json();
  await processNewContacts(data.results);
}, 5 * 60 * 1000);

When to use polling: When the third-party service doesn’t support webhooks. Simple use cases where real-time isn’t required.

Problems with polling: Inefficient (99% of polls find no new data), delays (up to 5 minutes in the example above), API rate limit consumption.

Webhooks

The third-party service sends your server a notification when an event occurs:

Event occurs in Stripe → Stripe sends POST request to your webhook URL → Your server processes it

Webhooks are real-time, efficient, and push-based. They’re the right architecture for:
– Payment confirmations
– CRM updates
– Form submission notifications
– Booking confirmations

Webhook endpoint best practices:

// /api/webhook-handler.js
export async function POST(request) {
  // 1. Verify the webhook signature (always)
  const isValid = await verifyWebhookSignature(request);
  if (!isValid) {
    return new Response('Unauthorized', { status: 401 });
  }

  // 2. Parse the event
  const event = await request.json();

  // 3. Acknowledge receipt IMMEDIATELY (before processing)
  // Stripe and others will retry if they don't get a 200 within 30 seconds
  const responsePromise = Response.json({ received: true }, { status: 200 });

  // 4. Process asynchronously
  processEventAsync(event).catch(err => {
    console.error('Webhook processing error:', err);
  });

  return responsePromise;
}

10. Error Handling and Security

Retry Logic with Exponential Backoff

API calls fail. Networks drop. Rate limits hit. Implement retry logic:

async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      // Rate limited — wait and retry
      if (response.status === 429) {
        const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
        await sleep(retryAfter * 1000);
        continue;
      }

      // Server error — retry with backoff
      if (response.status >= 500 && attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s
        await sleep(delay);
        continue;
      }

      return response;
    } catch (networkError) {
      if (attempt === maxRetries) throw networkError;
      await sleep(Math.pow(2, attempt) * 1000);
    }
  }
}

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

Security: Never Expose API Keys in Frontend

// ❌ NEVER — key is visible in browser source
const response = await fetch('/api/data', {
  headers: { 'Authorization': `Bearer sk_live_realkey` }
});

// ✅ CORRECT — key stays on your server
// Frontend calls your API route
const response = await fetch('/api/my-endpoint', {
  method: 'POST',
  body: JSON.stringify({ action: 'create-contact', data: formData })
});

// Your server (API route) makes the call to third-party API
// using environment variable — never exposed to client

Webhook Security: Signature Verification

Always verify webhook authenticity. Stripe, HubSpot, and most platforms sign their webhooks with HMAC-SHA256:

// Generic HMAC webhook signature verification
import crypto from 'crypto';

function verifyHmacSignature(payload, signature, secret) {
  const expectedSig = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  // Use timingSafeEqual to prevent timing attacks
  const sigBuffer = Buffer.from(signature);
  const expectedBuffer = Buffer.from(expectedSig);

  if (sigBuffer.length !== expectedBuffer.length) return false;
  return crypto.timingSafeEqual(sigBuffer, expectedBuffer);
}

Input Validation

Never pass form data directly to an API without validation:

import { z } from 'zod';

const contactSchema = z.object({
  email: z.string().email(),
  name: z.string().min(2).max(100),
  phone: z.string().regex(/^\+?[\d\s\-()]{7,20}$/).optional(),
  message: z.string().min(10).max(2000)
});

export async function POST(request) {
  const body = await request.json();

  // Validate before doing anything with the data
  const validated = contactSchema.safeParse(body);
  if (!validated.success) {
    return Response.json(
      { error: 'Invalid input', details: validated.error.issues },
      { status: 400 }
    );
  }

  // Now safe to use validated.data
  await createCRMContact(validated.data);
}

11. Interactive Tools

Tool 1: API Integration Planner

API Integration Planner

Select the integrations you need. Get a priority order, auth method, and implementation notes for each.


Tool 2: Webhook Debugging Checklist

Webhook Debugging Checklist

When your webhook isn’t working, go through this checklist in order.

0/16
Work through each item until the webhook fires correctly.


FAQ

Q: Should API calls happen in the browser (frontend) or on the server (backend)?
A: Always on the server for anything involving an API key, secret, or user data. Browser JavaScript is visible to anyone who opens DevTools. Server-side API calls (Node.js routes, serverless functions, PHP) keep your keys hidden and your data secure.

Q: What’s the difference between a webhook and an API call?
A: An API call is you requesting data from a service. A webhook is a service sending you data when an event occurs. You initiate API calls; services initiate webhooks. Webhooks are real-time and event-driven; polling via API calls is periodic and inefficient.

Q: How do I test webhooks locally during development?
A: Use ngrok (npm install -g ngrok). Run ngrok http 3000 to get a public HTTPS URL that tunnels to your local port 3000. Register this URL as your webhook endpoint in Stripe/HubSpot/Calendly. When events fire, they’ll reach your local server. Remember to update the URL when you restart ngrok (or pay for a fixed subdomain).

Q: What happens if my webhook endpoint is down and Stripe sends a payment confirmation?
A: Stripe (and most platforms) retry failed webhooks with exponential backoff — typically 3-5 attempts over 24-72 hours. If all retries fail, you’ll see it in the Stripe dashboard under Webhooks → Failed deliveries. You can manually redeliver failed webhooks from the dashboard. This is why your webhook endpoint must always return 200 quickly and process asynchronously.

Q: How do I handle API rate limits?
A: Implement retry logic with exponential backoff (shown in section 10). Check the API’s rate limit headers (X-RateLimit-Remaining, Retry-After). Cache responses where possible to reduce API calls. For batch operations, use bulk API endpoints (HubSpot batch create, etc.) instead of one request per item.

Q: Is it safe to use Zapier/Make instead of building custom API integrations?
A: For simple integrations (form → email notification, form → spreadsheet row), Zapier/Make are entirely appropriate and much faster to set up. For business-critical integrations (payment processing, real-time CRM sync, complex field mapping), a custom integration gives you more control over error handling, data validation, and business logic. Use the right tool for the complexity level.


Conclusion

API integrations transform a website from a static presence into a live business system. The form submission that becomes a CRM deal. The payment that triggers an automated onboarding sequence. The booking that creates a calendar event and sends a Slack notification. These aren’t technical niceties — they’re the difference between a website that generates leads and a website that grows your business.

Start with the highest-ROI integration for your situation: for most businesses, that’s form → CRM. Get it working reliably. Add payment APIs if ecommerce is in scope. Layer in calendar integrations and analytics as your automation matures.

Need a development team to build and maintain these integrations for your business? Ignited Nepal’s web development team builds connected websites with reliable, well-tested API integrations from day one.

Written by the Ignited Nepal team. ignitednepal.com

NR

Article by

Niraj Raut

Head of Search at Ignited Nepal. Drove 340% organic traffic growth for EzyDog (Australia), 4× revenue for The Turf Man (Australia), and 120% month-on-month traffic growth for ThemeGrill (Nepal). Keynote speaker at WordCamp Nepal 2023 and verified WordPress.org open-source contributor.