Back to Blog

How to stop free tier abuse on an API product

Developers rotate accounts and API keys to multiply your free tier. A playbook for stopping API free tier abuse without slowing down real developers.

A free tier is how most developers meet an API product. They sign up, get a key and build something before they pay. It's also an open invitation to free tier abuse: create another account, get another key, and the monthly allowance starts over. Do it ten times and one developer is running production traffic on your free tier.

It gets worse at scale. Scripted sign-ups can mint hundreds of free keys overnight and point all of them at your API at once. You pay for the compute behind every one of those calls, and the load can slow or take down the service for the paying customers who share it.

From our early beta

A team whose cloud bill normally ran $200 to $300 a month woke up to a $12,000 bill. Automated registrations had triggered thousands of expensive serverless functions, database operations and background jobs overnight.

Fake users drained one team's shared model provider quota. Their paying customers couldn't use the product until the team raised its budget to cover the abuse.

This playbook covers why rate limits don't stop this, where the check belongs, and how to protect a developer free tier without adding friction for the people you want to convert.

Why rate limits don't stop free tier abuse

Rate limits and quotas are counted per key or per account. That's exactly the boundary multi-accounting crosses. Every new account comes with a fresh key and a fresh allowance, and your gateway sees each one as a brand-new, well-behaved developer.

One developerAccount 1, key 1Account 2, key 2Account 3, key 3Full free allowanceFull free allowanceFull free allowance
One developerAccount 1, key 1Account 2, key 2Account 3, key 3Full free allowanceFull free allowanceFull free allowance

Your gateway is doing its job. It enforces usage within an account. What's missing is a check on whether the account should receive a free tier at all.

Where the check belongs

Protect the moment you grant the free tier, not every API call. AbuseZero evaluates the claim once, when a developer activates the free plan or receives their first key, and your gateway keeps enforcing usage as it does today.

[deny]alt[allow]Signs up and asks for a free keyEvaluate the free tier claimallow or deny, with a reasonIssue a key with the free allowanceKey readyChoose a paid plan to get a keyAPI calls, metered by your gatewayDeveloperYour dashboard and serverAbuseZeroYour API gatewayDeveloperYour dashboard and serverAbuseZeroYour API gateway
[deny]alt[allow]Signs upand asksfor a freekeyEvaluate thefree tierclaimallow ordeny, with areasonIssue a key with the freeallowanceKey readyChoose apaid plan toget a keyAPI calls, metered by your gatewayDeveloperYourdashboardandserverAbuseZeroYourAPIgatewayDeveloperYourdashboardandserverAbuseZeroYourAPIgateway

AbuseZero isn't in your API's request path. It doesn't meter calls or slow down your API. It decides who receives the free tier, and your application handles usage limits as it always has.

The playbook at a glance

DecisionRecommendation
BenefitThe free tier itself, claimed when the plan is activated or the first key is issued
EligibilityOnce per user. Add a second benefit for a monthly top-up, once per calendar month. See setting trial eligibility
When to checkBefore issuing the first free-tier key
Protection levelBalanced for most APIs; Strict when free usage carries real compute cost
IdentifiersEmail, IP address, device token from your sign-up page, payment method when collected
Your own identifiersThe ID of the account a developer signs in with, a company registration number or a tax ID, as custom identifiers
AutomationAssess. Developers automate everything, so judge claims, not tooling
HistoryImport existing free-tier accounts before you switch to protect

Use what only your business knows

API products often know things about a developer that no outside signal can: the account they signed in with, their company registration number, a tax ID from a billing profile. When a second account presents the same one, that link is strong.

AbuseZero's custom identifiers put that knowledge to work on every claim. You send each value as a keyed hash made with a secret only you hold, so the raw value never leaves your systems. Each custom identifier is checked against the benefit's complete claim history, exactly like the built-in identifiers, and becomes a condition you can use in your own rules.

Teams, companies and CI

  • Teams. If your free tier is meant per company, not per developer, claim it once per team and send a company or workspace ID as a custom identifier. Colleagues who join an existing team don't make a claim of their own, and a second free team for the same company is checked against the first.
  • CI and scripts. Developers automate their own workflows, and that's fine. The check runs on the free-tier claim, not on API traffic, so CI jobs and SDK calls against your API are never evaluated.
  • Returning developers. Someone who left a year ago and comes back isn't abusing anything. A rolling eligibility period can let them in again. See how to prevent free trial abuse.

Keep your free tier generous

Protection lets you keep a free tier worth trying, because one developer can't multiply it. Start with Builder or see pricing.

Add the check to key issuance

server/issue-free-key.ts
import { abusezero } from "@/lib/abusezero";

export async function issueFreeKey(
  developer: { id: string; email: string; emailVerified: boolean },
  claimId: string,
  ip: string,
  deviceToken: string,
) {
  const evaluation = await abusezero.evaluate(
    {
      benefit: "api_free_tier",
      claim_id: claimId,
      subject: { external_id: developer.id, email: developer.email, email_verified: developer.emailVerified },
      context: { ip },
      identifiers: { device_token: deviceToken },
    },
    `evaluate-${claimId}`,
  );

  if ("status" in evaluation || evaluation.result === "deny") {
    return { issued: false };
  }

  return { issued: true, key: await createApiKey(developer.id, "free") };
}

createApiKey stands for your own key service. To include your own identifiers, register them once and add their hashes to each evaluation. See custom identifiers. For the complete flow, see add a trial and credit abuse check to your signup flow.

Built for developer audiences

Your users are developers, and so are you. AbuseZero is available through the AbuseZero REST API, the AbuseZero Node.js SDK, the AbuseZero CLI and the AbuseZero MCP server, with the same actions and results on each. You can set up and tune your free-tier protection from your AI coding agent. See AbuseZero MCP server and CLI.

Frequently asked questions

How do I stop developers creating multiple accounts for more free API calls?

Check the free-tier claim before you issue the key. AbuseZero compares the claim with every free tier you've already granted, across changing emails, devices and networks, and returns allow or deny.

Do rate limits stop free tier abuse?

No. Rate limits count usage within one key or account. Free tier abuse spreads usage across many accounts, each with its own limit.

Does AbuseZero meter or slow down my API?

No. AbuseZero evaluates the free-tier claim once, when the benefit is granted. Your API traffic never passes through AbuseZero, and your gateway keeps enforcing usage limits.

Should a free API tier require a credit card?

A card requirement reduces abuse and reduces sign-ups. Checking each free-tier claim keeps sign-up card-free for real developers while stopping repeat accounts.

Can a team share one free tier?

Yes. Claim the free tier once per team and send a company or workspace ID as a custom identifier. Teammates join without a claim of their own, and a second free team for the same company is checked against the first.

Protect your free tier

Keep reading