How to Integrate with the Amplitude API: 2026 Engineering Guide for B2B SaaS
A definitive engineering guide to the Amplitude API in 2026. Learn how to architect reliable event ingestion, handle 429 rate limits, and prevent data loss.
If you are an engineering lead or product manager at a B2B SaaS company trying to push event data into Amplitude, you need to know three things immediately: which API endpoint to use, how to avoid getting throttled by Amplitude's per-user rate limits, and whether building a custom integration is worth the engineering time. If your B2B SaaS application cannot reliably sync customer data and events to Amplitude, your enterprise buyers will find a competitor who can.
Engineering teams tasked with building a product analytics integration often assume it is a simple matter of firing HTTP POST requests to an endpoint. That assumption breaks down in production the moment your application hits Amplitude's strict concurrency limits, drops critical event payloads, or fails to handle property updates at scale. This guide covers all the architectural specifics that Amplitude's own documentation buries across multiple pages.
The State of Product Analytics Integrations in 2026
Enterprise buyers do not purchase isolated software. They purchase nodes in a massive, interconnected graph of data. When a customer evaluates your SaaS product, they expect your platform to natively push usage metrics, feature flags, and conversion events directly into their central analytics stack. As your product grows and your customers demand tighter analytics integrations—what we classify as customer-facing integrations—the pressure to get event data flowing reliably only increases.
The global B2B SaaS market is projected to grow from $634 billion in 2026 to over $4.4 trillion by 2034 at a CAGR of 27.54%, according to Fortune Business Insights. This rapid expansion is driven by cloud adoption and the demand for AI-driven, operationalized analytics. Customers no longer tolerate manual CSV exports or brittle third-party middleware to move data from your application into Amplitude. If your integration drops events during traffic spikes, your customers' product managers and data scientists will immediately notice the discrepancies in their funnels and cohort analyses.
Amplitude HTTP V2 vs. Batch Event Upload API: Which Should You Use?
Amplitude provides two primary ingestion endpoints for event data. Choosing the wrong one for your architecture will result in immediate rate limiting or unacceptable latency. The HTTP V2 API is for real-time, low-latency event streaming. The Batch API is for high-volume backfills and server-side ingestion at scale.
Here is a breakdown of when to use each:
| Criteria | HTTP V2 API | Batch Event Upload API |
|---|---|---|
| Endpoint | https://api2.amplitude.com/2/httpapi |
https://api2.amplitude.com/batch |
| Throttle per user/device | 30 events/sec | 1,000 events/sec |
| Max payload size | 1 MB | 20 MB |
| Event ordering | Preserved per device_id |
Not guaranteed |
| Best for | Real-time user actions | Backfills, batch imports, server-side pipelines |
| EU endpoint | api.eu.amplitude.com/2/httpapi |
api.eu.amplitude.com/batch |
The HTTP V2 API
The Amplitude HTTP V2 API is designed for real-time event ingestion. It processes events in the exact order they are received for a given device_id, which makes it the right choice for tracking live user journeys where sequence matters—think funnel analysis or session replay correlation. If your SaaS application needs to trigger immediate downstream actions in a customer's stack, like firing an in-app message based on a specific user action, this is the endpoint to use.
The Batch Event Upload API
For high-volume data ingestion, the Amplitude Batch Event Upload API is mandatory. If your SaaS platform processes thousands of transactions, background jobs, or bulk imports on behalf of your users, attempting to push these through the HTTP V2 API will instantly trigger HTTP 429 Too Many Requests errors. The Batch API buffers data longer and is designed to absorb bursts, which makes it the obvious pick for nightly syncs, historical imports, or fan-out from webhook pipelines.
Architectural Tip: A common mistake is starting with the HTTP V2 API for everything, hitting the 30 events/sec per-user ceiling during load testing, and panic-migrating to the Batch API mid-sprint. Most B2B SaaS platforms should default to the Batch Event Upload API for server-to-server integrations. The slight delay in data availability is worth the massive reduction in network overhead and rate limit complexity.
Authentication and Security for the Amplitude API
Amplitude uses different authentication schemes depending on which API surface you are interacting with. Mixing these up will result in HTTP 401 Unauthorized errors.
Ingestion APIs (HTTP V2 and Batch)
For endpoints that write data into Amplitude, authentication is handled via an API Key included directly in the JSON request body as api_key—not as a header, and not as a query parameter. Most modern analytics APIs use Bearer tokens or header-based auth. Amplitude's approach is simpler but means your API key travels directly in the request payload.
{
"api_key": "YOUR_AMPLITUDE_API_KEY",
"events": [
{
"user_id": "user-9f3a2b",
"event_type": "feature_activated",
"time": 1714003200000,
"event_properties": {
"feature_name": "export_dashboard",
"plan": "enterprise"
},
"insert_id": "evt-9f3a2b-1714003200000"
}
]
}Never expose your Amplitude API key in client-side code. The event ingestion API keys are write-only, but a leaked key lets anyone write garbage events into your project. For B2B SaaS integrations, you should exclusively use server-side ingestion.
Dashboard REST API
If you need to query data out of Amplitude (for example, to pull cohort definitions back into your SaaS product), you must use the Dashboard REST API. This API requires Basic Authentication. You need to Base64-encode your API key and secret key as API_KEY:SECRET_KEY and pass it in the Authorization: Basic header. This distinction trips engineering teams up regularly.
Always store the Secret Key in a secure, encrypted vault. The API Key is generally safe to expose for client-side tracking, but the Secret Key grants full read/write access to the project's historical data.
Navigating Amplitude Rate Limits and 429 Errors
Handling rate limits is the single most complex part of building an Amplitude integration. Amplitude's infrastructure aggressively protects itself from misconfigured clients. They enforce three distinct rate limits, and conflating them is the fastest way to lose events in production:
- Per-user/device event throughput (HTTP V2): 30 events per second, averaged over a 30-second window. Exceeding this returns a
429withthrottled_usersandthrottled_devicesmaps in the response body. - Per-user/device event throughput (Batch API): 1,000 events per second, with a daily cap of 500,000 events per user/device.
- User property update limit: 1,800 updates per hour per user (by Amplitude ID). This applies across all APIs—HTTP V2, Batch, and the Identify API.
That third limit is the quiet killer. If your application is syncing user properties on every event (a common pattern when you use user_properties in the event payload), you can silently lose property updates without any error response. Amplitude keeps ingesting the standard events—it just stops applying the property changes entirely, leading to a silent desync between your database and the customer's Amplitude instance.
Architecting Exponential Backoff
When you receive an HTTP 429 error, you must not immediately retry the request. You must implement exponential backoff with jitter to prevent the "thundering herd" problem. Furthermore, the response body tells you exactly which users and devices were throttled.
Here is a practical, production-ready backoff implementation:
import time
import requests
import random
def send_to_amplitude(payload, max_retries=5):
url = "https://api2.amplitude.com/2/httpapi"
for attempt in range(max_retries):
response = requests.post(url, json=payload)
if response.status_code == 200:
return response.json()
if response.status_code == 429:
error_body = response.json()
throttled_users = error_body.get("throttled_users", {})
throttled_devices = error_body.get("throttled_devices", {})
# Log which users/devices are hot
for uid, rate in throttled_users.items():
print(f"User {uid} throttled at {rate} eps")
# Calculate exponential backoff: base_delay * 2^attempt
# Amplitude recommends a 30s pause for throttled identities
exponential_delay = 30 * (2 ** attempt)
# Add jitter to prevent synchronized retries across concurrent workers
jitter = random.uniform(0, 5)
# Cap the delay at the maximum allowed time (e.g., 5 minutes)
wait = min(exponential_delay + jitter, 300)
time.sleep(wait)
continue
if response.status_code in (500, 502, 504):
# Server error - retry with insert_id for dedup
time.sleep(2 ** attempt)
continue
# 400, 413, etc. - don't retry, fix the payload
response.raise_for_status()
raise Exception("Max retries exceeded for Amplitude ingestion")The key detail from Amplitude's documentation: when you get a 429 on the HTTP V2 API, you should pause sending events for that specific user or device for 30 seconds before retrying. This is not a global backoff—it is per-identity. If you are sending events for 10,000 users and only one is throttled, you should only pause that one user's events.
For a deeper look at rate limit handling across multiple third-party APIs simultaneously, see our guide on best practices for handling API rate limits and retries.
Event Deduplication with insert_id
Amplitude deduplicates events using a combination of device_id and insert_id within a rolling 7-day window. If you retry a failed request (especially after a 5xx server error), you must always include an insert_id to prevent duplicate events. Amplitude recommends generating a UUID or composing one from device_id + user_id + event_type + event_id + time.
This is not optional in production. Without insert_id, a single network timeout followed by a retry can double-count a revenue event or artificially inflate your activation metrics.
Architecting a Reliable Webhook-to-Amplitude Pipeline
The typical B2B SaaS pattern looks like this: your application fires internal events (a ticket closing, a payment succeeding, or a user role changing), and you need those events to land in a customer's Amplitude instance reliably. Building this as a direct synchronous call from your app's main thread to Amplitude is a severe anti-pattern for three reasons:
- Amplitude downtime blocks your app. If the Amplitude API returns a 503 and you are making synchronous calls, your user-facing request hangs.
- Burst traffic exceeds rate limits. A product launch or marketing campaign can easily spike your event volume past the 30 events/sec per-user limit.
- No replay capability. When Amplitude has an outage, you lose events unless you have a durable buffer.
To ensure zero data loss, you must architect a durable webhook fan-out system.
flowchart LR
A[SaaS App Core] -->|Fires Event| B[Internal Event Bus]
B -->|Routes to| C[Webhook Ingestion Service]
C -->|Validates & Enqueues| D[(Durable Queue)]
D -->|Pulls Batch by user_id| E[Worker Pool]
E -->|Transforms Payload| F{Amplitude Batch API}
F -- HTTP 200 --> G[Mark Complete]
F -- HTTP 429 --> H[Calculate Backoff & Re-queue]
F -- HTTP 500 --> HKey Components for Reliability
- Decoupled Ingestion: Your core application should drop events into an internal message broker or event bus and immediately return a success response to the user.
- Durable Queuing & Partitioning: Workers pull from a durable queue. If a worker crashes mid-flight, the message remains in the queue to be processed by another node. Crucially, you must partition your queue by
user_idordevice_id. Because Amplitude's throttling is per-identity, if one spammy user triggers a 429, you want that to only block that user's partition—not your entire pipeline. - Payload Transformation: Amplitude requires specific JSON schemas. Your worker must map your internal data model (e.g.,
ticket.status = closed) to the customer's desired Amplitude event taxonomy. - Dead-Letter Queues (DLQ): If an event fails to sync after maximum retries (e.g., due to a malformed payload or a revoked API key), it must be routed to a DLQ for engineering review, rather than infinitely blocking the queue.
For patterns on building reliable webhook fan-out systems, including signature verification and delivery guarantees, see our production lessons in designing reliable webhooks.
Amplitude API Gotchas That Will Bite You in Production
Beyond rate limits and architecture, there are several strict payload constraints that Amplitude's documentation mentions but does not emphasize enough. These will cause immediate 400 Bad Request errors if ignored:
- Minimum ID length: Both
user_idanddevice_idmust be at least 5 characters long. Shorter values are silently stripped from the event. If an event has neither a validuser_idnordevice_id, Amplitude rejects it. Reserved strings like"null","undefined","anonymous", and"none"are also invalid. - Time must be epoch milliseconds: Sending ISO 8601 timestamps in the
timefield returns a 400 error. However, every other field that represents a date should be ISO 8601. Yes, this is inconsistent. - String values cap at 1,024 characters: This includes
user_id, event names, and property values. If you are passing long JSON blobs as event properties, they will be silently truncated. - The
$skip_user_properties_syncflag: If you are sending high-volume events and do not need user property updates on every single event, set this flag totrue. It avoids hitting the silent 1,800/hour user property limit and reduces Amplitude's processing overhead. - 413 Payload Too Large thresholds differ by API: HTTP V2 rejects payloads over 1 MB. The Batch API rejects payloads over 20 MB. If you are dynamically batching events, your batch size logic needs to know exactly which endpoint you are targeting.
The Real Cost of a Custom Amplitude Integration
When a sales prospect asks for an Amplitude integration—much like when evaluating an Intercom integration—engineering teams often look at the documentation and estimate the work at a few days. They build a simple HTTP client, hardcode the JSON mappings, and ship it. This point-to-point approach is a trap.
The initial build is never the expensive part. The true cost of a custom integration lies in the permanent maintenance burden. Here is what happens next:
- Week 2: You discover the 30 events/sec limit during load testing and realize you need to build the durable queuing system detailed above.
- Month 2: A customer on a high-traffic plan is silently losing user property updates because you hit the 1,800/hour limit without realizing it.
- Month 4: Amplitude introduces new required fields or changes their error response format for 400 errors, and your custom parser breaks.
- Month 6: Your EU customers need data sent to
api.eu.amplitude.comand you realize you hardcoded the US endpoint in your core application logic. - Month 8: Enterprise Customer A wants the event named
Account Upgraded, while Customer B requires it to be namedsubscription_tier_changed. Hardcoding these mappings becomes impossible, forcing you to build a custom mapping UI.
This is the integration treadmill. Each point-to-point connection looks trivial in isolation, but the cumulative maintenance cost compounds. Every hour your senior engineers spend debugging a dropped Amplitude event is an hour they are not building your core product.
How Truto Simplifies Amplitude Integrations for B2B SaaS
Truto is designed specifically to eliminate the maintenance burden of customer-facing integrations. By utilizing a unified API and zero-code architecture, your team can offer a native Amplitude integration without writing or maintaining a custom API client.
Instead of writing custom Python or Node.js code for each integration, Truto uses a declarative configuration system. Every API connector is defined as a set of JSON configurations that map your data model to the provider's API schema using JSONata expressions. This means you have zero integration-specific code in your runtime.
What this means for your Amplitude integration specifically:
Transparent Rate Limit Handling
When Amplitude returns a 429, Truto passes that response directly to your application with standardized ratelimit-limit, ratelimit-remaining, and ratelimit-reset headers following the IETF specification. Your code decides how to handle backoff cleanly—Truto does not silently retry or absorb errors on your behalf. This is a deliberate design choice: opaque retry middleware can drop events or create duplicates without your internal systems ever knowing.
Unified Webhook Fan-Out
If you need to ingest events from your SaaS application and reliably route them to Amplitude, you can leverage Truto's unified webhook infrastructure. Your application simply fires a standard webhook to Truto. Truto handles the ingestion, applies the per-customer JSONata transformations to match their specific Amplitude taxonomy, and manages the outbound delivery to the Amplitude Batch API without requiring you to build a custom listener or queue.
Schema Mapping Without Code
Adding Amplitude (or switching from Amplitude to Mixpanel, or adding a HubSpot integration) is a configuration change, not a code change. The JSONata mapping layer transforms your unified event schema to whatever the target API expects, handling the nuances of custom taxonomies instantly.
There is an honest trade-off here. Using a unified API platform means adding a dependency in your data path. For teams that need absolute control over every byte sent to Amplitude and have dedicated integration engineers, building in-house makes sense. But for teams that need to ship 10+ integrations this quarter without draining their core engineering resources, the abstraction layer pays for itself rapidly.
What to Do Next
If you are building an Amplitude integration today, start with these steps:
- Choose your endpoint: Real-time user actions go to HTTP V2. Backfills, syncs, and server-side pipelines go to Batch. Do not try to use one endpoint for both.
- Always send
insert_id: Event deduplication is not optional in production. Generate a UUID for every single event payload. - Decouple ingestion from your app: Use an internal message queue between your application and Amplitude. Partition by
user_idordevice_idto isolate throttling. - Monitor user property sync separately: The 1,800/hour limit is silent. Track how many property updates you are sending per user and alert when you approach the threshold.
- Evaluate build vs. buy honestly: If Amplitude is your only analytics integration and your event volume is low, building in-house is reasonable. If you need to support multiple analytics platforms across different customer segments, the maintenance cost of point-to-point integrations compounds fast, a challenge we've explored in how mid-market SaaS teams handle API rate limits and webhooks at scale.
The Amplitude API itself is well-designed and well-documented compared to many enterprise SaaS APIs. The pitfalls are in the operational details—rate limits, silent property drops, endpoint-specific payload limits—that only surface under heavy production load. Plan for them upfront, and you will save yourself a painful midnight debugging session later.
FAQ
- Should I use the Amplitude HTTP V2 API or the Batch Event Upload API?
- Use the HTTP V2 API for real-time, low-volume event tracking where sequence matters. For high-volume server-to-server integrations, historical data migrations, or webhook fan-outs, you must use the Batch API, which accepts up to 1000 events per second per device ID.
- What is the rate limit for the Amplitude HTTP V2 API?
- Amplitude enforces a strict limit of 30 events per second for individual users or devices on the HTTP V2 API, measured as an average over a 30-second window. Exceeding this triggers HTTP 429 errors.
- How do you prevent duplicate events in Amplitude?
- Include an insert_id field in every event. Amplitude deduplicates events with the same device_id and insert_id within a rolling 7-day window. Generate a UUID or combine device_id, user_id, event_type, and timestamp.
- What happens when Amplitude's user property update limit is exceeded?
- Amplitude silently drops user property updates after 1,800 updates per hour per user, but continues ingesting standard events normally. There is no error response, making this limit particularly dangerous to miss in production.
- How does Truto handle Amplitude 429 rate limit errors?
- Truto passes upstream 429 rate limit errors directly back to the caller without applying internal retries or opaque backoff. It normalizes the rate limit data into standard IETF headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) so your system can dynamically handle retries.