Skip to content

Backend

Public API + Rate Limits — When Velocity X Customers Build Their Own Integrations

REST endpoints, per-tenant rate limits, and the SLA that keeps integrations honest.

🔌 📊

Your mid-market customer signs a contract. By week two, they've got a legacy ERP system that needs to push data into Velocity X every night. By week three, they want a Zapier integration. By week four, they're building their own webhook receiver in Slack. Your question: how do you scale the API without letting one customer's runaway script take down service for everyone else?

Velocity X solves this with a public REST API gated behind per-tenant rate limits: 1000 requests per minute, per authentication token. Requests beyond that hit a 429 (Too Many Requests) response. No surprise invoices, no shared resource starvation, no customer support fires. It's the difference between building infrastructure for partners and just hoping they play nice.

Why a Public API Beats Custom Integrations

Without a public API, customers ask for custom data connectors. You build bespoke ETL for their ERP. You maintain it. When they upgrade their ERP version, you debug why the data mapper broke. You're now in the integration business, not the SaaS business.

A public API flips the incentive: customers build what they need. They own the integration code. If it breaks after their ERP upgrade, they fix it—or hire a contractor who gets paid to maintain it, not you. You ship one API spec and support it forever; they own N integrations and maintain them. That's leverage.

The catch? Without rate limits, a customer's runaway script (a bug, a loop, a cronjob set to 1-second intervals) can hammer your infrastructure. Unbounded requests → database connection pool exhaustion → slow queries for paying users → outage. Rate limits enforce resource fairness: one tenant can't monopolise the system.

Architecture: Auth Tokens + Per-Tenant Rate Limiting

Velocity X uses API keys (opaque tokens) tied to a tenant account. Customers generate a key in their dashboard, use it in the Authorization: Bearer <token> header, and get 1000 req/min. Here's how it flows:

{`curl -X POST https://api.velocityx.app/v1/integrations \\
  -H "Authorization: Bearer vx_9a8b7c6d5e4f3a2b1c0d" \\
  -H "Content-Type: application/json" \\
  -d '{"name": "ERP Sync", "destination": "production"}'

// Response (if under quota):
{
  "id": "int_5f4e3d2c1b0a9876",
  "name": "ERP Sync",
  "created_at": "2026-06-13T10:45:00Z"
}

// Response (if over quota):
{
  "error": "rate_limit_exceeded",
  "retry_after_seconds": 42,
  "current_window": "2026-06-13T10:46:00Z"
}`}

The middleware on the API layer checks the Authorization header, looks up the token in a table, increments a sliding-window counter (same Postgres + TTL pattern we covered for form submission rate limiting), and decides: allow or 429. All within 3ms.

How the Sliding Window Works at 1000 req/min

A sliding window doesn't reset at a fixed hour boundary (which allows bursts); it tracks requests within the last 60 seconds. If a customer makes 1000 requests between 10:00:00 and 10:00:59, they're at quota. At 10:00:01, the request from 10:00:00 falls out of the window, and they get one new slot. This prevents gaming; you can't make 2000 requests by waiting exactly 60 seconds and hammering again.

{`-- Rate limit table per token
CREATE TABLE api_rate_limits (
  token_id UUID NOT NULL,
  request_count INT DEFAULT 1,
  window_start TIMESTAMP DEFAULT NOW(),
  PRIMARY KEY (token_id)
);

-- On each request:
-- 1. SELECT window_start and request_count where token_id = ?
-- 2. If (NOW() - window_start) > 60 seconds, reset count to 1
-- 3. Else if count >= 1000, return 429
-- 4. Else increment count, allow request
-- 5. Return count + remaining quota to the response headers
-- X-RateLimit-Limit: 1000
-- X-RateLimit-Remaining: 842
-- X-RateLimit-Reset: 2026-06-13T10:46:12Z`}

The response headers tell the client exactly how much quota is left and when the window resets. Well-built integrations watch these headers and throttle automatically. Poorly-built ones spam until they hit 429, then retry with exponential backoff (which is fine—the rate limiter wins).

Why 1000 req/min is the Right Number

Too low (100 req/min): Legitimate integrations starve. A customer syncing 50K records across 10 batches? Blocked halfway. Support tickets spike. You get a reputation for a slow API.

Too high (10K req/min): A misbehaving script can still flood the database. One tenant's bug affects others. You end up rebuilding rate limits anyway.

1000 req/min: ~16 requests per second. Enough for bursty workloads (a webhook flood, a catch-up sync) without risking multi-tenant blast radius. For context: a well-written integration batch-syncing 100K records takes 1.67 minutes. Slower than a direct API call, but acceptable for asynchronous workflows. And customers who need 5K+ req/min can upgrade to an Enterprise plan with higher limits—that becomes a revenue conversation, not a support nightmare.

Webhook Delivery + Rate Limiting Interaction

Velocity X also sends webhooks (e.g., order.created, shipment.updated) to customer endpoints. The server retries failed webhooks 5 times with exponential backoff (10s, 1m, 10m, 1h, 24h). If a customer's endpoint is overloaded and rejects requests, Velocity X backs off—not the other way around. Rate limits protect Velocity X; customer retry logic is their problem to solve.

However, if a customer calls the API AND receives webhooks, they effectively have two traffic streams. The rate limit applies to API calls only, not inbound webhooks. This is intentional: we won't penalise a customer for receiving data we're pushing to them.

SLA: 99.9% Uptime for Authenticated Endpoints

Velocity X commits to 99.9% uptime on all authenticated API endpoints (documented in the contract and at /pricing). That's 43 minutes of downtime per month. In practice, we hit 99.95% most months. The rate limiter itself is part of this guarantee: if the middleware fails open or closed, it's a partial outage, and we count it against the SLA.

This matters for customer integration teams. If your ERP sync runs every night and Velocity X is down, the sync fails and triggers an alert. If we're down 44 minutes/month, you'll see it. Good integrations have retry logic; better ones have a status dashboard they can check before running a critical sync.

Common Integration Patterns (and Their Bandwidth)

Nightly batch sync (100K records, 10 batches of 10K): 10 API calls, each ~500ms. Total: 5 seconds of wall time, 10 requests against quota. Safe.

Real-time webhook → re-sync: Customer receives a webhook (e.g., order.ready), calls the API to fetch the full order and associated items. 3 API calls per webhook. If 100 orders/day hit, that's 300 requests/day = 0.2 req/min. Safe, with headroom.

Polling fallback (no webhook support): Customer polls the API every 5 minutes for new records. 288 requests/day = 0.2 req/min. Also safe. If they want sub-minute polling, that's 1440 requests/day = 1 req/min per polling interval. Still under quota.

Bulk import (1M records in 1 day): 100 batches of 10K = 100 API calls, spread over 24 hours = 0.07 req/min per request. Easy. But if they try to do it in 1 hour, that's 100 req/min. Still under 1000, but close. A smart integration would add jitter or space calls out.

OpenAPI Spec Auto-Generation

Velocity X publishes an OpenAPI 3.0 spec. Customers (and tools like Zapier, Make, Postman) use it to auto-generate SDK stubs and documentation. This happens behind the scenes; customers don't need to know. But it keeps the API self-documenting: if you add a new endpoint, the spec updates automatically, and integrations can regenerate their SDKs.

Common Questions

Can I get a higher rate limit?

Yes. Contact sales or upgrade to Enterprise. We handle per-customer limits on a case-by-case basis if there's a legitimate use case (e.g., real-time syncing 10K records/min). Default is 1000 req/min; Enterprise might get 10K or unlimited depending on infrastructure.

What happens if I go over my limit?

You get a 429 response with a Retry-After header. The response is JSON: {"error": "rate_limit_exceeded", "retry_after_seconds": 42}. Your integration should respect this and wait before retrying. Hammering while over-limit just wastes bandwidth.

Is the rate limit per API key or per account?

Per API key. If you generate multiple keys (e.g., one for ERP sync, one for Zapier), each has its own 1000 req/min budget. This lets you isolate workloads and kill a key if it's misbehaving without blocking everything else.

Can I whitelist my IP to skip rate limiting?

No. Rate limits apply to all requests. But if you're on a static IP and suspect you're hitting legitimate spikes, generate a new key and rotate. Rate limits reset per key; stale requests under the old key don't count.

How long does a 429 response take?

Still 3ms. The middleware decides you're over-quota and returns immediately. You don't pay for the request in terms of database load. This is important: rate limiting protects your infrastructure *before* your business logic runs.

The Bottom Line

A public API with per-tenant rate limits is table-stakes for any SaaS platform that wants customers to build on top of it. 1000 req/min per token is a sweet spot: fast enough for most integrations, slow enough to prevent runaway scripts from taking down the platform. Pair it with an OpenAPI spec, clear error responses, and SLA commitment, and you've got a product developers want to build against. Skip the rate limiting? You'll spend the next 3 months debugging customer integration failures and outages. Build it right the first time.

Let us make some quick suggestions?

Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.