---
title: "API Governance"
description:
  "Define security and compliance policies once, apply them across every route,
  enforce them in CI before merge. Explore implementation details and next
  steps."
canonicalUrl: "https://zuplo.com/features/api-governance"
sourceUrl: "https://zuplo.com/features/api-governance"
pageType: "feature"
generatedAt: "2026-10-21"
---

# Policy as code, enforced before merge

> When every team configures auth and rate limits its own way, governance
> becomes a manual review queue. Define your policies once and enforce them in
> CI on every route — so compliance stops taxing your velocity.

The hero shows an animated example of a governance check on a pull request ("Add
/v2/checkout endpoints", touching 6 routes). Four rules pass:
`auth-required-on-all-routes` (6/6 routes have `api-key-auth-inbound`),
`rate-limit-shared-policy` (all routes inherit `rate-limit-prod`),
`request-validation` (OpenAPI schemas validated), and `audit-log-export`
(consumer-id captured on every request).

## Governance by Slack message doesn't survive the next audit

When policy lives in conventions instead of code, every team interprets it
differently. The auditor finds the gap. The compliance review extends the
launch. The CISO loses sleep.

- **Each team enforces its own definition of "production-ready"** — Three teams,
  three rate-limit conventions, three logging formats. Auditors ask "how do you
  ensure all APIs require auth?" and the honest answer is "we Slack each team
  and hope."
- **Compliance reviews block ship velocity** — A new endpoint takes two
  engineering days to implement and two weeks to clear "the security review."
  The slowdown is the cost of not having policy enforced automatically.
- **Audit logs scattered across five places** — Authentication logs in Auth0,
  gateway logs in CloudWatch, app logs in Datadog, deploy logs in GitHub,
  account changes in your IDP. Compiling a single audit trail for one customer
  takes a sprint.
- **"Who changed the prod rate limit at 2am?"** — A control-plane click changed
  something critical. There's no PR, no diff, no immutable audit. Engineering
  manager spends Monday morning piecing together the timeline from Slack DMs.

## Define it once. Enforce it in CI. Audit it forever.

- **One policy, every route** — Define rate limits, auth, schema validation, and
  audit logging once as a shared policy or composite. Reference it from every
  route. Update it once — every route inherits.
- **Enforced in your PR, not after deploy** — Config is files in Git. CI runs
  your governance checks before merge — auth required on every route, no inline
  rate limits, schema validation on body-bearing requests. Violations block the
  merge.
- **SOC 2 audit, not Slack archaeology** — Every config change is a Git commit.
  Every account action is in the immutable audit log with full actor and
  resource context. Every gateway request is logged with caller identity and
  exported to your SIEM. One place per dimension, all queryable.

## One bundle. Every route. Reviewed in a PR.

Wrap your "production-ready" requirements into a single named Composite Inbound
policy. Apply it to every public route. Run a governance check in CI to fail any
PR that ships a route without it.

Production-ready composite policy:

```json
{
  "name": "production-ready-inbound",
  "policyType": "composite-inbound",
  "handler": {
    "export": "CompositeInboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "policies": [
        "api-key-auth-inbound",
        "rate-limit-prod",
        "request-validation-inbound",
        "audit-log-datadog"
      ]
    }
  }
}
```

```text
# Apply to every route in routes.oas.json:
# x-zuplo-route.policies.inbound:
# - production-ready-inbound
```

Governance check in CI (`.github/workflows/governance.yml`):

```yaml
- name: Enforce production-ready policy
  run: |
    node scripts/check-governance.mjs
```

`scripts/check-governance.mjs` (excerpt):

```js
for (const [path, route] of Object.entries(routes.paths)) {
  for (const [method, op] of Object.entries(route)) {
    const policies = op["x-zuplo-route"]?.policies?.inbound ?? [];
    if (!policies.includes("production-ready-inbound")) {
      console.error(
        `${method.toUpperCase()} ${path} ` +
          " missing production-ready-inbound",
      );
      process.exit(1);
    }
  }
}
```

## Compliance you can show, not pay a consultant to assemble

- **OpenAPI is the source of truth** — Routes live in `config/routes.oas.json` —
  a standard OpenAPI document with `x-zuplo-*` extensions for handlers and
  policies. Lint with Spectral in CI, generate clients with Speakeasy or
  RateMyOpenAPI, write tests against the schema. The gateway and the docs and
  the SDKs all read the same file.
- **Composite policies as governance bundles** — Bundle "production-ready" into
  a Composite Inbound policy: api-key-auth → rate-limit-prod →
  request-validation → audit-log-export. Apply the composite to every public
  route. New routes inherit the full policy stack with one line — no opportunity
  to forget a step.
- **Account-level immutable audit** — Every project mutation, deployment, team
  change, API key operation — captured with full actor (sub, email, IP, geo,
  ASN), resource (type/ID), and outcome. 90-day default retention, query via
  Developer API, export to your SIEM. Pre-baked for SOC 2 evidence collection.
- **Data residency on your terms** — Managed Edge for global low latency.
  Managed Dedicated single-tenant on the cloud and region of your choice
  (EU-only, US-only, regulated cloud) when sovereignty requires it. Self-Hosted
  on your Kubernetes when nothing leaves your perimeter. Same policies, every
  surface.

## What teams use this for

> "Auditor needs proof every API requires authentication."

Show them `config/policies.json` (one shared `api-key-auth-inbound` policy), the
Composite Inbound bundle that includes it, and your CI script that fails if any
route doesn't reference the composite. Three files, one queryable Git history,
one minute.

> "We need to roll out a new rate limit across 47 routes."

Update the shared `rate-limit-prod` policy in one place. Every route that
references it inherits the new value. Open a PR. Reviewers see one diff, one
test run, one merge — instead of 47 individual changes.

> "Customer wants 12 months of audit logs for a SOC 2 review."

Export the account audit log via the Developer API to your S3-backed log
archive. Combined with gateway logs in your SIEM (Datadog, Splunk, etc.), you
have an immutable trail covering both control-plane changes and data-plane
traffic — exactly what the auditor wants.

> "Force partners off a deprecated API version on a known schedule."

Attach the Brownout policy to the deprecated routes. It returns scheduled 503s
during specified windows — first an hour a week, then a day, then full sunset —
so partners feel the deprecation as concrete downtime instead of an email they
ignored. The policy lives in your repo with a date-driven config; no last-minute
pull-the-plug ops.

## Frequently Asked Questions

Common questions about API governance and compliance on Zuplo.

### What is API governance?

API governance is the practice of enforcing consistent rules — auth, rate
limits, schema validation, logging, deprecation — across every API in your
organization. Without it, each team ships its own version of "production-ready"
and auditors get vague answers. Zuplo treats governance as code: shared policies
you define once, apply to every route, and validate in CI before merge. SOC 2
evidence, audit trails, and policy enforcement become a Git history instead of a
Slack archaeology dig.

### How do you enforce consistent policies across every API?

Define each policy — auth, rate limit, schema validation, audit logging — once
as a shared resource in your gateway config, then reference it by name from
every route. Bundle the common stack into a Composite Inbound policy and apply
the bundle in one line per route. New routes inherit the full policy stack
automatically; updates roll out to every route the moment you merge. Zuplo's
GitOps-first model means every governance change is a reviewable PR.

### Is Zuplo SOC 2 compliant?

Yes — Zuplo is SOC 2 Type II certified. The current report and Trust Center are
published at trust.zuplo.com. Beyond Zuplo's own posture, the platform is built
to support your SOC 2, HIPAA, and enterprise security reviews: immutable audit
logs, RBAC for the management plane, encryption at rest and in transit,
GitOps-based change history, and exportable audit trails to your SIEM.

### How do I get an audit trail of who changed an API config?

Every config change in Zuplo is a Git commit — author, diff, message, timestamp
— so the answer to "who changed the prod rate limit at 2am" is one git blame
away. On top of that, the account-level audit log captures every project
mutation, deployment, team change, and API key operation with full actor
identity (email, IP, geo) and resource context. 90-day default retention,
immutable, queryable via the Developer API, exportable to your SIEM.

### How do I enforce API security policies in CI before merge?

Because Zuplo's config is files in your Git repo, any rule you can write as a
script can run in CI. Common patterns: every route must reference an auth
policy, no inline rate limits (must use a shared one), schema validation
required on body-bearing requests, audit-log policy on every public route. Wire
the script into a GitHub Action and block the merge if it fails. Governance
becomes a guardrail, not a quarterly review.

### How do you keep API data in a specific region for compliance?

Zuplo offers three deployment models depending on how strict your data residency
needs to be. Managed Edge runs across 300+ data centers globally for low
latency. Managed Dedicated is a single-tenant instance in the cloud and region
you choose — EU-only, US-only, regulated cloud, etc. Self-Hosted runs on your
own Kubernetes when nothing leaves your perimeter. Same policies, same
dashboards, contractually enforced location.

### How do I enforce API deprecation and force partners off old versions?

Most teams email a deprecation notice and pray. Zuplo has a Brownout policy that
turns deprecation into scheduled downtime — attach it to deprecated routes with
a ramp (one hour weekly, then a day, then full sunset) and partners feel
concrete 503s during the window. Combine with Deprecation headers and the
developer portal's banners and partners get a structured, dated path off the old
version. Schedule lives in your repo, reviewable in a PR.

### What's the best API gateway for SOC 2 and enterprise compliance?

Look for SOC 2 Type II certification, GitOps-native config (so every change is
auditable), immutable account audit logs, RBAC for the management plane,
exportable logs to your SIEM, and configurable data residency. Zuplo ships all
of these out of the box and is used by regulated customers in fintech,
healthcare, and banking — including BancoSol, LMCU, and BlockDaemon. Talk to a
Zuplo compliance expert to walk through your specific framework.

## Next steps

Compliance shouldn't slow shipping. Free Zuplo project, define one shared
policy, apply it to every route — and watch your CI block the next governance
regression before it merges.

- [Start for Free](https://portal.zuplo.com/signup)
- [Read the Policies Guide](https://zuplo.com/docs/articles/policies)
- [Talk to a Compliance Expert](/schedule-call)
- [Read Trust & Security](https://trust.zuplo.com/)
