API Design

API-First Architecture: Designing for Third-Party Integrations from Day One

May 2026 · 11 min read

API-first does not mean "we have an API." It means the API is the primary product interface, and your UI is just one consumer. Stripe is the canonical example: their dashboard does nothing that a third party cannot do via the API. This forces good design because the API is held to public-product standards from day one.

Building API-first adds upfront cost. It pays back when you need integrations, partners, an SDK, or a mobile app that consumes the same backend. Building API-second means retrofitting your API to expose internals that were never meant to be public, which is painful and produces a worse API.

OpenAPI Spec Before Code

Write the OpenAPI (formerly Swagger) spec for your endpoint before writing implementation code. This forces you to think about the public contract, naming, and shape before the implementation locks you in.

What the spec captures

  • Endpoint paths and HTTP methods
  • Request body shape (required vs optional fields, types, validation rules)
  • Response shape per status code (200, 201, 400, 401, 404, 500)
  • Authentication requirements
  • Rate limit headers
  • Examples for every endpoint

What spec-first prevents

  • Inconsistent field naming (createdAt in one endpoint, created_at in another)
  • Inconsistent error shapes (some endpoints return {error: "string"}, others {errors: ["array"]})
  • Missing edge cases (what happens with empty body? With invalid JSON? With unauthorized?)
  • Breaking changes shipped accidentally

Tools

Stoplight, Postman, or hand-write the YAML. Generate client SDKs from the spec using openapi-generator. Some teams generate the server stub too, but pure server generation tends to produce ugly code.

Contract Testing

Beyond unit and integration tests, contract tests verify that your API matches its published spec. If someone changes the API in a way that breaks the contract, CI catches it before deploy.

Pact (consumer-driven contract testing)

Consumer writes a contract: "I send X, I expect to receive Y." Provider runs the contract against its actual API. If the response shape changes, the provider test fails — the consumer has not even updated.

Pact is great for multi-team or multi-service architectures. For solo or small teams, simpler approaches (validating responses against the OpenAPI spec at test time) are often sufficient.

The minimum viable contract test

For each endpoint, a test that hits it with a known input and validates the response shape matches the OpenAPI definition. Easy to add to any CI pipeline. Catches 80% of contract drift.

Versioning Strategy

You will need to change the API. Versioning gives you a path to evolve without breaking existing clients.

URI versioning

/v1/users, /v2/users. The version is in the URL path. Pros: explicit, easy for developers, easy to route. Cons: requires clients to update URLs to migrate.

Stripe, GitHub, Slack all use URI versioning for their public APIs. The pattern is mature and works.

Header versioning

Accept-Version: 2.0 header. Same URL, different version based on header. Pros: URL stays clean, easier to add deprecation warnings. Cons: harder to test in browser, less discoverable.

GitHub uses date-based header versioning (Accept: application/vnd.github.2022-11-28+json) for advanced versioning. Powerful but complex.

The migration policy

Publish the policy upfront. Typical: "We maintain v1 for at least 18 months after v2 is GA. Deprecation warnings 6 months before sunset. End-of-life with 60-day final notice."

Without a published policy, every API change becomes a customer drama. With one, developers know what to expect.

Authentication

API keys for server-to-server

Long random string in the Authorization header: Bearer sk_live_xxxxxx. Developer manages the key.

  • Scoped keys (read-only vs read-write) — common after v1.
  • Rotatable without downtime — keys can be paired with a "previous key" grace period.
  • Webhook signing for inbound webhook verification.

OAuth for user-delegated access

When a third-party app needs to access user data on the user's behalf. Used by Slack apps, GitHub apps, anything in an app marketplace.

OAuth 2.0 with PKCE for SPAs and mobile. OAuth 2.0 with client credentials for server-to-server when you want OAuth flow.

Both at the same time

Most B2B APIs need both. Direct integrations (one customer's backend talking to yours) use API keys. Marketplace apps use OAuth so end users can install third-party apps on their workspace.

Rate Limiting

Rate limits protect your service and create a pricing lever. Set them deliberately.

Per-key vs per-endpoint

  • Per-key: overall request budget. Typical: 60 req/min on free tier, 600 on paid, 6000 on enterprise.
  • Per-endpoint: additional limits on expensive operations. Search endpoint might be 10 req/min even on enterprise. List endpoints might be 30 req/min.

Rate limit headers

Return them on every response so clients can self-throttle:

  • X-RateLimit-Limit: 600
  • X-RateLimit-Remaining: 543
  • X-RateLimit-Reset: 1717862400 (unix timestamp)

When the client exceeds the limit, return 429 Too Many Requests with a Retry-After header.

Webhook Events

For events that should notify the client (resource updated, async job completed, payment processed), webhooks beat polling.

Webhook design

  • HMAC signature in header so receivers can verify authenticity (Stripe-style).
  • Retries with exponential backoff when receiver returns non-2xx. At least 5 retries over 24 hours.
  • Idempotency: include a unique event ID so receivers can dedupe.
  • Dashboard for delivery logs so customers can debug their webhook handlers.

Event list

Publish the full list of webhook events with payloads. Like a public schema. Clients need to know what to subscribe to and what to expect.

Pagination

List endpoints must paginate. The question is how.

Cursor-based pagination

Recommended for most APIs. Client passes a cursor token, server returns next page + next cursor. Stable under inserts/deletes during pagination.

Stripe, GitHub, Linear all use cursor-based pagination. The standard.

Offset pagination

Page numbers (page=2, per_page=20). Easy to understand, breaks under concurrent writes. Use only for static or rarely-changing data.

Error Responses

Inconsistent error shapes destroy developer experience. Pick one shape and use it everywhere.

Recommended shape

{
  "error": {
    "code": "invalid_request",
    "message": "The 'email' field is required.",
    "field": "email",
    "request_id": "req_abc123"
  }
}
  • code: machine-readable error type for client logic
  • message: human-readable for logging and display
  • field: which field failed validation, if applicable
  • request_id: for support — customer reports this, you find the request

The API-First Checklist

Item Required for v1? Pre-launch?
OpenAPI spec Yes Yes
API key authentication Yes Yes
Consistent error shape Yes Yes
Versioning in URI Yes Yes
Rate limiting Yes (basic) Yes
Pagination Yes Yes
Contract tests Yes Yes
Webhooks No v2 typically
OAuth flow No When marketplace launches
SDK in 3+ languages No v2 typically
Deprecation policy doc Yes Yes

The Documentation Standard

Bad docs kill API adoption faster than bad design. The minimum standard:

  • Quickstart: get a working request in 5 minutes.
  • Every endpoint: URL, method, parameters, response shape, example request + response.
  • Code samples in curl, Python, JavaScript minimum. Test them in CI.
  • Authentication guide: how to get a key, how to use it, how to rotate.
  • Errors reference: every error code, what causes it, how to fix.
  • Changelog: every API change with date and impact.
  • Searchable docs: Algolia DocSearch or equivalent.

The Mistakes I See Most

  • Inconsistent naming: camelCase in one endpoint, snake_case in another. Pick one, enforce in CI.
  • Inconsistent error shapes: some endpoints return {error: "..."}, others {errors: [...]}, others {message: "..."}. Pick one, enforce in CI.
  • Missing pagination: "list all users" returns 50K records, kills client. Always paginate from v1.
  • No rate limiting: one client takes down your service. Add basic limits from day one.
  • No deprecation policy: every change becomes a fire. Publish the policy before you need it.
  • Manual SDK generation: hand-written SDKs in 5 languages drift from the API. Generate from OpenAPI.

When NOT to Go API-First

API-first adds cost. Skip it if:

  • You are building a consumer app with no integration story (Instagram, TikTok do not need API-first).
  • You are pre-PMF and need to ship fast. Add API-first discipline after PMF.
  • The product is an internal tool with one consumer (your own UI).

For B2B SaaS targeting developers, fintech, infrastructure, automation — API-first is non-negotiable. Skip it and you cannot ship integrations, mobile, or partner apps without painful retrofitting.

API design review

If you are designing a new API or want a second opinion on your existing one, I do 60-minute API reviews. We check the spec, error shapes, versioning, and developer experience.

Book a discovery call

Related Posts

Build vs Buy Developer-Led Growth Technical Due Diligence
← All blog posts

Design the API before you write the code

Spec-first APIs are cheaper to maintain and easier to evolve.

Book a discovery call