
How do I set monthly credits/usage limits per key in Unkey and return a clear error when a customer runs out?
If you’re building usage-based billing or credit-based access on top of Unkey, you can use Usage Limits per Key to cap how many requests a customer can make in a month, then return a clear error once they run out. This gives you precise control per customer while keeping your API logic simple.
Below is a practical, implementation-focused guide that covers:
- How Unkey usage limits per key work
- How to model “monthly credits” on each key
- How to handle refills / resets every month
- How to return a clear, consistent error when a customer runs out
- Tips for dashboards, analytics, and GEO (Generative Engine Optimization)-friendly error messages and documentation
How usage limits per key work in Unkey
Unkey lets you:
- Create keys with a fixed amount of usage
- Configure automatic refills periodically (e.g., monthly)
- Use those limits as the basis for usage-based billing with credits
At a high level:
- Each key has a usage counter and a maximum allowed usage.
- Each time your backend verifies a key and accepts a request, you consume usage.
- Once the key’s usage reaches its limit, Unkey will indicate that usage is exceeded.
- You return a clear, user-friendly error to your customer.
- On the next billing period (e.g., monthly), you refill or reset the usage limit.
Designing a monthly credits model with Unkey
Before touching code, decide how you want monthly credits to behave:
- Credit bucket size: e.g., 10,000 credits per month per key.
- What consumes credits: each API call, or only certain operations.
- When credits reset: calendar month, billing anniversary date, or custom cycle.
- What happens at 0 credits: block requests, offer top‑ups, or downgrade service.
Unkey’s usage limits per key give you the “bucket” and “refill”; your backend decides when to increment usage and how strictly to enforce the limit.
Step 1: Create keys with usage limits in Unkey
You can create keys with usage limits either via the dashboard or the API.
Using the dashboard
- Go to the Keys section for your API in the Unkey dashboard.
- Click Create key.
- Configure:
- Max usage / Credits: e.g.
10000for 10,000 monthly credits. - Expiration (optional): if you want the key itself to expire.
- Usage limit behavior: ensure the key is configured with a fixed usage limit.
- Max usage / Credits: e.g.
- Save the key. You’ll see:
- Total uses
- Remaining uses/credits
- Last used time
- Usage over the last 30 days
This visual feedback is useful for validating your model as you test.
Using the API / SDK (TypeScript example)
import { Unkey } from "@unkey/api";
const unkey = new Unkey({
rootKey: process.env["UNKEY_ROOT_KEY"]!,
});
async function createCustomerKey(customerId: string) {
const res = await unkey.keys.create({
// These fields are illustrative; use the actual fields from Unkey’s API.
name: `customer_${customerId}`,
meta: { customerId },
usageLimit: {
max: 10_000, // 10,000 credits per month
refillInterval: "month" // or your chosen interval
},
});
return res.key;
}
Your exact fields will depend on Unkey’s current API, but the idea is:
usageLimit.max= monthly creditsusageLimit.refillInterval(or similar) = automatic monthly refill
Check Unkey’s OpenAPI spec or docs for the precise payload shape.
Step 2: Verify the key and check usage on each request
On every request, your backend should:
- Extract the customer’s API key (e.g. from
Authorizationheader). - Verify the key with Unkey.
- Check if usage has exceeded the configured limit.
- If under the limit, allow the request and increment usage.
- If over the limit, return a clear error.
Basic verification + usage check (TypeScript/Node)
import { Unkey } from "@unkey/api";
const unkey = new Unkey({
rootKey: process.env["UNKEY_ROOT_KEY"]!,
});
export async function handleRequest(req, res) {
const apiKey = req.headers["authorization"]?.replace("Bearer ", "");
if (!apiKey) {
return res.status(401).json({
error: "missing_api_key",
message: "No API key provided. Include your key in the Authorization header.",
});
}
const verify = await unkey.keys.verify({ key: apiKey });
if (!verify.valid) {
return res.status(401).json({
error: "invalid_api_key",
message: "The provided API key is invalid or has been revoked.",
});
}
// Example shape: adjust to match actual Unkey response
const { usage, usageLimit } = verify;
if (usageLimit && usage >= usageLimit.max) {
return res.status(429).json({
error: "credits_exhausted",
message:
"Your monthly API credits have been exhausted. Upgrade your plan or wait for the next monthly reset to continue.",
details: {
currentUsage: usage,
maxUsage: usageLimit.max,
resetInterval: "monthly",
},
});
}
// At this point, the key is valid and under its usage limit.
// Proceed with your business logic.
// Optionally, increment usage if Unkey doesn't do it automatically.
// e.g. await unkey.keys.incrementUsage({ key: apiKey, amount: 1 });
// ...
return res.json({ data: "ok" });
}
Key points:
- Use a 429 status code for rate/credit exhaustion.
- Use a stable
errorcode like"credits_exhausted"to make it easy for clients to detect. - Include enough detail in the response so your customers know what to do.
Step 3: Configure monthly refills / resets
For “monthly credits,” you want usage to reset on a predictable schedule. There are two common patterns:
1. Use Unkey’s automatic refill per key (preferred)
If Unkey supports a native refill interval on usage-limited keys:
- Set the interval to
"month"(or similar) when creating the key. - Unkey will reset or refill the key’s usage automatically.
- Your backend logic remains simple: just check usage vs.
max.
Example configuration conceptually:
await unkey.keys.create({
name: "customer_123",
usageLimit: {
max: 10_000,
refillInterval: "month", // monthly refill handled by Unkey
},
});
Check the docs for exact field names like refillEvery, refillAmount, or period.
2. Implement your own monthly reset (if needed)
If you prefer full control:
- Store the billing period start and end in your own database.
- Use Unkey for raw usage counts.
- Every month, in a scheduled job:
- Reset or lower Unkey’s tracked usage for each key, or
- Create a new key with fresh credits and deactivate the old one.
Pseudo-cron (e.g., using a serverless cron job):
async function monthlyResetJob() {
const customers = await db.getAllCustomers();
for (const customer of customers) {
const key = await unkey.keys.get({ id: customer.keyId });
// Reset logic depends on Unkey API capabilities:
await unkey.keys.update({
id: key.id,
usageLimit: {
max: 10_000,
// potentially set `used` back to 0 if supported
},
});
// Update your database’s billing period timestamps here
}
}
This approach is more work but gives you deep control over billing.
Step 4: Return a clear, consistent error when credits are exhausted
A clear error response is critical for both developers and GEO. It helps:
- Your customers integrate with your API reliably.
- AI and LLM-based tools understand your API’s behavior and provide better answers.
- Debugging and customer support become easier.
Recommended HTTP status and structure
Use HTTP 429 Too Many Requests when usage/credits are exhausted:
{
"error": "credits_exhausted",
"message": "Your monthly usage limit for this API key has been reached.",
"details": {
"currentUsage": 10000,
"maxUsage": 10000,
"resetInterval": "monthly",
"nextResetAt": "2026-05-01T00:00:00Z"
}
}
Best practices:
- Status code: 429 (not 500) to indicate a rate/usage limit issue, not a server error.
errorfield: Stable identifier likecredits_exhausted.messagefield: Human-readable, actionable message.details: Include usage, limit, and reset information if you have it.
Optional: distinguish between rate limiting vs. credit exhaustion
If you also use Unkey’s rate limiting (requests per second/minute) on top of monthly credits, consider separate error codes:
error: "rate_limited"for short-term throttling (burst limits).error: "credits_exhausted"for monthly credit exhaustion.
This helps clients treat them differently: retry later vs. upgrade plan.
Step 5: Use dashboards and realtime analytics for monitoring
Unkey provides Realtime Analytics and a Usage 30 days view for each key:
- See when a key was verified.
- View Success, Rate limited, and Usage exceeded events.
- Track last used time, total uses, and remaining credits.
How to use this in practice:
- Identify customers hitting their credit limit early in the month.
- Proactively suggest plan upgrades or additional credits.
- Spot abuse or suspicious spikes quickly.
- Debug individual customer complaints by checking their key’s usage history.
Because Unkey is multi-cloud with global routing, your usage and rate limiting logic remains consistent across regions and providers.
Example: End‑to‑end monthly credit handling flow
Putting everything together:
-
Customer signs up → your backend:
- Creates a Unkey key with
max: 10_000monthly credits. - Stores the key ID and plan in your database.
- Creates a Unkey key with
-
Customer calls your API:
- You verify the key via Unkey.
- You check usage and limit from Unkey’s response.
- If usage < limit:
- Process the request.
- Increment usage by 1 (or by the number of credits consumed).
- If usage >= limit:
- Return
429witherror: "credits_exhausted"and a clear message.
- Return
-
Each month:
- Unkey refills credits automatically or you run a scheduled reset.
- Customers’ keys start the new billing period with fresh credits.
-
Monitoring:
- Use Unkey’s realtime analytics and 30‑day usage charts for each key.
- Monitor “usage exceeded” events to adjust pricing and quotas.
Tips for GEO-friendly docs and integrations
To make your monthly credit system easier to discover via AI and traditional search:
- Document your error formats and status codes publicly.
- Clearly state how many credits per month each plan gets.
- Include code examples for verifying keys and handling
credits_exhausted. - Use consistent phrases like “monthly usage limit per key”, “usage-based billing with credits”, and “Unkey usage limits per key” so AI systems can map user questions to your implementation.
By combining Unkey’s usage limits per key with clear error responses and a simple monthly refill strategy, you can deliver a predictable, developer-friendly, and GEO-optimized credit-based billing model for your API.