Quotas
Quotas in Ductape enforce usage limits and track resource consumption across your product. They allow you to define maximum usage thresholds and automatically manage access based on consumption.
What is a Quota?
A quota is a usage limit system that:
- Defines maximum usage thresholds for resources or features
- Tracks consumption across multiple quota options (tiers, plans, etc.)
- Supports both execution (runtime checking) and configuration (CRUD operations)
- Can integrate with features and actions
- Maintains usage counters and enforces limits
Use quotas for:
- Rate limiting - Limit API calls per user/tenant
- Subscription tiers - Enforce plan-specific usage limits
- Resource management - Control access to premium features
- Fair usage - Prevent abuse and ensure equitable access
Creating a Quota
Create a quota using ductape.quota.create():
- TypeScript
- Java
- Go
- .NET
import Ductape from '@ductape/sdk';
import { FeatureEventTypes, DataTypes } from '@ductape/sdk/types';
const ductape = new Ductape({
accessKey: 'your-access-key',
});
await ductape.quota.create({
name: 'API Call Quota',
tag: 'api-calls',
description: 'Limits API calls per subscription tier',
input: {
userId: { type: DataTypes.STRING },
plan: { type: DataTypes.STRING },
},
total_quota: 10000, // Total quota across all options
total_init: 10000, // Initial total quota value
options: [
{
quota: 1000, // Free tier: 1000 calls
uses: 0, // Current usage (tracked automatically)
type: FeatureEventTypes.ACTION,
event: 'check-free-tier',
app: 'billing-service',
input: { userId: '$Input{userId}' },
output: { remaining: '$Response{remaining}' },
retries: 1,
},
{
quota: 10000, // Pro tier: 10000 calls
uses: 0,
type: FeatureEventTypes.ACTION,
event: 'check-pro-tier',
app: 'billing-service',
input: { userId: '$Input{userId}' },
output: { remaining: '$Response{remaining}' },
retries: 1,
},
],
});
import app.ductape.sdk.Ductape;
import app.ductape.sdk.core.EnvType;
import app.ductape.sdk.core.RequestContext;
import Map.of( FeatureEventTypes, DataTypes ) from '@ductape/sdk/types';
RequestContext auth = new RequestContext(null, null, null, null, 'your-access-key');
Ductape ductape = new Ductape(EnvType.PRODUCTION, auth);
ductape.quota.create(Map.of(
"name", "API Call Quota",
"tag", "api-calls",
"description", "Limits API calls per subscription tier",
input: Map.of(
userId: Map.of( type: DataTypes.STRING ),
plan: Map.of( type: DataTypes.STRING ),
),
"total_quota", 10000, // Total quota across all options
"total_init", 10000, // Initial total quota value
options: [
Map.of(
"quota", 1000, // Free "tier", 1000 calls
"uses", 0, // Current usage (tracked automatically)
type: FeatureEventTypes.ACTION,
"event", "check-free-tier",
"app", "billing-service",
input: Map.of( "userId", "$InputMap.of(userId)" ),
output: Map.of( "remaining", "$ResponseMap.of(remaining)" ),
"retries", 1,
),
Map.of(
"quota", 10000, // Pro "tier", 10000 calls
"uses", 0,
type: FeatureEventTypes.ACTION,
"event", "check-pro-tier",
"app", "billing-service",
input: Map.of( "userId", "$InputMap.of(userId)" ),
output: Map.of( "remaining", "$ResponseMap.of(remaining)" ),
"retries", 1,
),
],
));
import (
"context"
"github.com/ductape/ductape/sdk/go/core"
"github.com/ductape/ductape/sdk/go/ductape"
)
import { FeatureEventTypes, DataTypes } from '@ductape/sdk/types';
auth := core.NewRequestContext("", "", "", "", 'your-access-key')
client, err := client.New(core.EnvProduction, auth)
if err != nil {
return err
}
client.quota.create({
"name": "API Call Quota",
"tag": "api-calls",
"description": "Limits API calls per subscription tier",
input: {
userId: { type: DataTypes.STRING },
plan: { type: DataTypes.STRING },
},
"total_quota": 10000, // Total quota across all options
"total_init": 10000, // Initial total quota value
options: [
{
"quota": 1000, // Free "tier": 1000 calls
"uses": 0, // Current usage (tracked automatically)
type: FeatureEventTypes.ACTION,
"event": "check-free-tier",
"app": "billing-service",
input: { "userId": "$Input{userId}" },
output: { "remaining": "$Response{remaining}" },
"retries": 1,
},
{
"quota": 10000, // Pro "tier": 10000 calls
"uses": 0,
type: FeatureEventTypes.ACTION,
"event": "check-pro-tier",
"app": "billing-service",
input: { "userId": "$Input{userId}" },
output: { "remaining": "$Response{remaining}" },
"retries": 1,
},
],
});
using Ductape.Sdk;
using Ductape.Sdk.Core;
import { FeatureEventTypes, DataTypes } from '@ductape/sdk/types';
var auth = new RequestContext(null, null, null, null, 'your-access-key', null);
var ductape = new Ductape(EnvType.Production, auth);
await ductape.quota.create({
["name"] = "API Call Quota",
["tag"] = "api-calls",
["description"] = "Limits API calls per subscription tier",
input: {
userId: { type: DataTypes.STRING },
plan: { type: DataTypes.STRING },
},
["total_quota"] = 10000, // Total quota across all options
["total_init"] = 10000, // Initial total quota value
options: [
{
["quota"] = 1000, // Free ["tier"] = 1000 calls
["uses"] = 0, // Current usage (tracked automatically)
type: FeatureEventTypes.ACTION,
["event"] = "check-free-tier",
["app"] = "billing-service",
input: { ["userId"] = "$Input{userId}" },
output: { ["remaining"] = "$Response{remaining}" },
["retries"] = 1,
},
{
["quota"] = 10000, // Pro ["tier"] = 10000 calls
["uses"] = 0,
type: FeatureEventTypes.ACTION,
["event"] = "check-pro-tier",
["app"] = "billing-service",
input: { ["userId"] = "$Input{userId}" },
output: { ["remaining"] = "$Response{remaining}" },
["retries"] = 1,
},
],
});
Quota Fields
| Field | Type | Description |
|---|---|---|
name | string | Display name for the quota |
tag | string | Unique identifier |
description | string | Description of what the quota limits |
input | Record<string, IFeatureInput> | Input schema definition |
total_quota | number | Maximum total quota across all options |
total_init | number | Initial quota value |
options | IQuotaOptions[] | Array of quota tiers/options |
Quota Option Fields
Each option in the options array has:
| Field | Type | Description |
|---|---|---|
quota | number | Maximum allowed usage for this option |
uses | number | Current usage count (tracked automatically) |
type | FeatureEventTypes | Type of action to execute (ACTION or FEATURE) |
event | string | Tag of the action/feature to execute |
app | string | App tag (if type is ACTION) |
input | object | Input mapping for the action |
output | object | Output mapping from the action |
retries | number | Number of retry attempts |
healthcheck | string | Optional healthcheck tag |
Running a Quota
Execute quota checks at runtime using ductape.quota.run():
- TypeScript
- Java
- Go
- .NET
const result = await ductape.quota.run({
tag: 'api-calls',
input: {
userId: 'user123',
plan: 'free',
},
session: {
tag: 'user-session',
token: 'session-token',
},
cache: 'quota-cache', // Optional: cache quota checks
});
console.log('Quota result:', result);
// Check if quota exceeded
if (result.exceeded) {
console.log('Quota limit reached!');
} else {
console.log(`Remaining: ${result.remaining}`);
}
Map<String, Object> result = ductape.quota.run(Map.of(
"tag", "api-calls",
input: Map.of(
"userId", "user123",
"plan", "free",
),
session: Map.of(
"tag", "user-session",
"token", "session-token",
),
"cache", "quota-cache", // Optional: cache quota checks
));
System.out.println('Quota "result", ", result);
// Check if quota exceeded
if (result.exceeded) Map.of(
System.out.println("Quota limit reached!');
) else Map.of(
System.out.println(`Remaining: $Map.of(result.remaining)`);
)
result := client.quota.run({
"tag": "api-calls",
input: {
"userId": "user123",
"plan": "free",
},
session: {
"tag": "user-session",
"token": "session-token",
},
"cache": "quota-cache", // Optional: cache quota checks
});
fmt.Println('Quota "result": ", result);
// Check if quota exceeded
if (result.exceeded) {
fmt.Println("Quota limit reached!');
} else {
fmt.Println(`Remaining: ${result.remaining}`);
}
var result = await ductape.quota.run({
["tag"] = "api-calls",
input: {
["userId"] = "user123",
["plan"] = "free",
},
session: {
["tag"] = "user-session",
["token"] = "session-token",
},
["cache"] = "quota-cache", // Optional: cache quota checks
});
Console.WriteLine('Quota ["result"] = ", result);
// Check if quota exceeded
if (result.exceeded) {
Console.WriteLine("Quota limit reached!');
} else {
Console.WriteLine(`Remaining: ${result.remaining}`);
}
Run Parameters
| Parameter | Type | Description |
|---|---|---|
env | string | Environment (e.g., 'dev', 'prd') |
product | string | Product tag |
tag | string | Quota tag to execute |
input | object | Input data for quota check |
session | object | Optional session information |
cache | string | Optional cache tag |
Fetching Quotas
Get All Quotas
- TypeScript
- Java
- Go
- .NET
const quotas = await ductape.quota.fetchAll();
quotas.forEach(quota => {
console.log(`${quota.name} (${quota.tag})`);
console.log(`Total: ${quota.total_quota}`);
quota.options.forEach((option, i) => {
console.log(` Option ${i}: ${option.uses}/${option.quota}`);
});
});
Map<String, Object> quotas = ductape.quota.fetchAll();
quotas.forEach(quota => Map.of(
System.out.println(`$Map.of(quota.name) ($Map.of(quota.tag))`);
System.out.println(`Total: $Map.of(quota.total_quota)`);
quota.options.forEach((option, i) => Map.of(
System.out.println(` Option $Map.of(i): $Map.of(option.uses)/$Map.of(option.quota)`);
));
));
quotas := client.quota.fetchAll();
quotas.forEach(quota => {
fmt.Println(`${quota.name} (${quota.tag})`);
fmt.Println(`Total: ${quota.total_quota}`);
quota.options.forEach((option, i) => {
fmt.Println(` Option ${i}: ${option.uses}/${option.quota}`);
});
});
var quotas = await ductape.quota.fetchAll();
quotas.forEach(quota => {
Console.WriteLine(`${quota.name} (${quota.tag})`);
Console.WriteLine(`Total: ${quota.total_quota}`);
quota.options.forEach((option, i) => {
Console.WriteLine(` Option ${i}: ${option.uses}/${option.quota}`);
});
});
Get a Specific Quota
- TypeScript
- Java
- Go
- .NET
const quota = await ductape.quota.fetch('api-calls');
console.log('Quota:', quota.name);
console.log('Description:', quota.description);
console.log('Total Quota:', quota.total_quota);
console.log('Options:', quota.options.length);
Map<String, Object> quota = ductape.quota.fetch('api-calls');
System.out.println('"Quota", ", quota.name);
System.out.println(""Description", ", quota.description);
System.out.println("Total "Quota", ", quota.total_quota);
System.out.println("Options:', quota.options.length);
quota := client.quota.fetch('api-calls');
fmt.Println('"Quota": ", quota.name);
fmt.Println(""Description": ", quota.description);
fmt.Println("Total "Quota": ", quota.total_quota);
fmt.Println("Options:', quota.options.length);
var quota = await ductape.quota.fetch('api-calls');
Console.WriteLine('["Quota"] = ", quota.name);
Console.WriteLine("["Description"] = ", quota.description);
Console.WriteLine("Total ["Quota"] = ", quota.total_quota);
Console.WriteLine("Options:', quota.options.length);
Updating Quotas
Update quota configuration using ductape.quota.update():
- TypeScript
- Java
- Go
- .NET
await ductape.quota.update('api-calls', {
total_quota: 50000, // Increase total quota
options: [
{
quota: 5000, // Increase free tier
type: FeatureEventTypes.ACTION,
event: 'check-free-tier',
app: 'billing-service',
input: { userId: '$Input{userId}' },
output: { remaining: '$Response{remaining}' },
retries: 1,
},
{
quota: 50000, // Increase pro tier
type: FeatureEventTypes.ACTION,
event: 'check-pro-tier',
app: 'billing-service',
input: { userId: '$Input{userId}' },
output: { remaining: '$Response{remaining}' },
retries: 1,
},
],
});
ductape.quota.update('api-calls', Map.of(
"total_quota", 50000, // Increase total quota
options: [
Map.of(
"quota", 5000, // Increase free tier
type: FeatureEventTypes.ACTION,
"event", "check-free-tier",
"app", "billing-service",
input: Map.of( "userId", "$InputMap.of(userId)" ),
output: Map.of( "remaining", "$ResponseMap.of(remaining)" ),
"retries", 1,
),
Map.of(
"quota", 50000, // Increase pro tier
type: FeatureEventTypes.ACTION,
"event", "check-pro-tier",
"app", "billing-service",
input: Map.of( "userId", "$InputMap.of(userId)" ),
output: Map.of( "remaining", "$ResponseMap.of(remaining)" ),
"retries", 1,
),
],
));
client.quota.update('api-calls', {
"total_quota": 50000, // Increase total quota
options: [
{
"quota": 5000, // Increase free tier
type: FeatureEventTypes.ACTION,
"event": "check-free-tier",
"app": "billing-service",
input: { "userId": "$Input{userId}" },
output: { "remaining": "$Response{remaining}" },
"retries": 1,
},
{
"quota": 50000, // Increase pro tier
type: FeatureEventTypes.ACTION,
"event": "check-pro-tier",
"app": "billing-service",
input: { "userId": "$Input{userId}" },
output: { "remaining": "$Response{remaining}" },
"retries": 1,
},
],
});
await ductape.quota.update('api-calls', {
["total_quota"] = 50000, // Increase total quota
options: [
{
["quota"] = 5000, // Increase free tier
type: FeatureEventTypes.ACTION,
["event"] = "check-free-tier",
["app"] = "billing-service",
input: { ["userId"] = "$Input{userId}" },
output: { ["remaining"] = "$Response{remaining}" },
["retries"] = 1,
},
{
["quota"] = 50000, // Increase pro tier
type: FeatureEventTypes.ACTION,
["event"] = "check-pro-tier",
["app"] = "billing-service",
input: { ["userId"] = "$Input{userId}" },
output: { ["remaining"] = "$Response{remaining}" },
["retries"] = 1,
},
],
});
Using Quotas in Features
Reference quotas in your feature workflows to enforce limits:
- TypeScript
- Java
- Go
- .NET
import { FeatureEventTypes, DataTypes } from '@ductape/sdk/types';
await ductape.features.create({
tag: 'send-notification',
name: 'Send Notification with Quota',
input: {
userId: { type: DataTypes.STRING },
message: { type: DataTypes.STRING },
},
events: [
// Check quota first
{
type: FeatureEventTypes.QUOTA,
event: 'notification-quota',
input: {
userId: '$Input{userId}',
},
},
// If quota allows, send notification
{
type: FeatureEventTypes.ACTION,
event: 'send-push',
app: 'notification-service',
input: {
userId: '$Input{userId}',
message: '$Input{message}',
},
condition: {
left: '$Sequence{notification-quota}{exceeded}',
operator: 'equals',
right: false,
},
},
],
});
import Map.of( FeatureEventTypes, DataTypes ) from '@ductape/sdk/types';
ductape.features.create(Map.of(
"tag", "send-notification",
"name", "Send Notification with Quota",
input: Map.of(
userId: Map.of( type: DataTypes.STRING ),
message: Map.of( type: DataTypes.STRING ),
),
events: [
// Check quota first
Map.of(
type: FeatureEventTypes.QUOTA,
"event", "notification-quota",
input: Map.of(
"userId", "$InputMap.of(userId)",
),
),
// If quota allows, send notification
Map.of(
type: FeatureEventTypes.ACTION,
"event", "send-push",
"app", "notification-service",
input: Map.of(
"userId", "$InputMap.of(userId)",
"message", "$InputMap.of(message)",
),
condition: Map.of(
"left", "$SequenceMap.of(notification-quota)Map.of(exceeded)",
"operator", "equals",
"right", false,
),
),
],
));
import { FeatureEventTypes, DataTypes } from '@ductape/sdk/types';
client.features.create({
"tag": "send-notification",
"name": "Send Notification with Quota",
input: {
userId: { type: DataTypes.STRING },
message: { type: DataTypes.STRING },
},
events: [
// Check quota first
{
type: FeatureEventTypes.QUOTA,
"event": "notification-quota",
input: {
"userId": "$Input{userId}",
},
},
// If quota allows, send notification
{
type: FeatureEventTypes.ACTION,
"event": "send-push",
"app": "notification-service",
input: {
"userId": "$Input{userId}",
"message": "$Input{message}",
},
condition: {
"left": "$Sequence{notification-quota}{exceeded}",
"operator": "equals",
"right": false,
},
},
],
});
import { FeatureEventTypes, DataTypes } from '@ductape/sdk/types';
await ductape.features.create({
["tag"] = "send-notification",
["name"] = "Send Notification with Quota",
input: {
userId: { type: DataTypes.STRING },
message: { type: DataTypes.STRING },
},
events: [
// Check quota first
{
type: FeatureEventTypes.QUOTA,
["event"] = "notification-quota",
input: {
["userId"] = "$Input{userId}",
},
},
// If quota allows, send notification
{
type: FeatureEventTypes.ACTION,
["event"] = "send-push",
["app"] = "notification-service",
input: {
["userId"] = "$Input{userId}",
["message"] = "$Input{message}",
},
condition: {
["left"] = "$Sequence{notification-quota}{exceeded}",
["operator"] = "equals",
["right"] = false,
},
},
],
});
Access quota results in subsequent events using sequence syntax:
- TypeScript
- Java
- Go
- .NET
{
type: FeatureEventTypes.ACTION,
event: 'log-quota-status',
input: {
remaining: '$Sequence{notification-quota}{remaining}',
limit: '$Sequence{notification-quota}{limit}',
exceeded: '$Sequence{notification-quota}{exceeded}',
},
}
Map.of(
type: FeatureEventTypes.ACTION,
"event", "log-quota-status",
input: Map.of(
"remaining", "$SequenceMap.of(notification-quota)Map.of(remaining)",
"limit", "$SequenceMap.of(notification-quota)Map.of(limit)",
"exceeded", "$SequenceMap.of(notification-quota)Map.of(exceeded)",
),
)
{
type: FeatureEventTypes.ACTION,
"event": "log-quota-status",
input: {
"remaining": "$Sequence{notification-quota}{remaining}",
"limit": "$Sequence{notification-quota}{limit}",
"exceeded": "$Sequence{notification-quota}{exceeded}",
},
}
{
type: FeatureEventTypes.ACTION,
["event"] = "log-quota-status",
input: {
["remaining"] = "$Sequence{notification-quota}{remaining}",
["limit"] = "$Sequence{notification-quota}{limit}",
["exceeded"] = "$Sequence{notification-quota}{exceeded}",
},
}
Example: Multi-Tier API Quota
- TypeScript
- Java
- Go
- .NET
import Ductape from '@ductape/sdk';
import { FeatureEventTypes, DataTypes } from '@ductape/sdk/types';
const ductape = new Ductape({
accessKey: 'your-access-key',
});
await ductape.product.init('api-platform');
// Create quota with multiple tiers
await ductape.quota.create({
name: 'Monthly API Requests',
tag: 'monthly-api-quota',
description: 'API request limits per subscription plan',
input: {
userId: { type: DataTypes.STRING },
tier: { type: DataTypes.STRING },
},
total_quota: 1000000,
total_init: 1000000,
options: [
{
quota: 1000, // Hobby: 1K/month
uses: 0,
type: FeatureEventTypes.ACTION,
event: 'check-tier',
app: 'quota-service',
input: { tier: 'hobby' },
output: { allowed: '$Response{allowed}' },
retries: 2,
},
{
quota: 10000, // Starter: 10K/month
uses: 0,
type: FeatureEventTypes.ACTION,
event: 'check-tier',
app: 'quota-service',
input: { tier: 'starter' },
output: { allowed: '$Response{allowed}' },
retries: 2,
},
{
quota: 100000, // Pro: 100K/month
uses: 0,
type: FeatureEventTypes.ACTION,
event: 'check-tier',
app: 'quota-service',
input: { tier: 'pro' },
output: { allowed: '$Response{allowed}' },
retries: 2,
},
],
});
// Run quota check
const check = await ductape.quota.run({
tag: 'monthly-api-quota',
input: {
userId: 'user123',
tier: 'starter',
},
});
if (check.exceeded) {
console.log('API quota exceeded - upgrade required');
} else {
console.log(`Quota OK - ${check.remaining} requests remaining`);
}
import app.ductape.sdk.Ductape;
import app.ductape.sdk.core.EnvType;
import app.ductape.sdk.core.RequestContext;
import Map.of( FeatureEventTypes, DataTypes ) from '@ductape/sdk/types';
RequestContext auth = new RequestContext(null, null, null, null, 'your-access-key');
Ductape ductape = new Ductape(EnvType.PRODUCTION, auth);
ductape.product.init('api-platform');
// Create quota with multiple tiers
ductape.quota.create(Map.of(
"name", "Monthly API Requests",
"tag", "monthly-api-quota",
"description", "API request limits per subscription plan",
input: Map.of(
userId: Map.of( type: DataTypes.STRING ),
tier: Map.of( type: DataTypes.STRING ),
),
"total_quota", 1000000,
"total_init", 1000000,
options: [
Map.of(
"quota", 1000, // "Hobby", 1K/month
"uses", 0,
type: FeatureEventTypes.ACTION,
"event", "check-tier",
"app", "quota-service",
input: Map.of( "tier", "hobby" ),
output: Map.of( "allowed", "$ResponseMap.of(allowed)" ),
"retries", 2,
),
Map.of(
"quota", 10000, // "Starter", 10K/month
"uses", 0,
type: FeatureEventTypes.ACTION,
"event", "check-tier",
"app", "quota-service",
input: Map.of( "tier", "starter" ),
output: Map.of( "allowed", "$ResponseMap.of(allowed)" ),
"retries", 2,
),
Map.of(
"quota", 100000, // "Pro", 100K/month
"uses", 0,
type: FeatureEventTypes.ACTION,
"event", "check-tier",
"app", "quota-service",
input: Map.of( "tier", "pro" ),
output: Map.of( "allowed", "$ResponseMap.of(allowed)" ),
"retries", 2,
),
],
));
// Run quota check
Map<String, Object> check = ductape.quota.run(Map.of(
"tag", "monthly-api-quota",
input: Map.of(
"userId", "user123",
"tier", "starter",
),
));
if (check.exceeded) Map.of(
System.out.println('API quota exceeded - upgrade required');
) else Map.of(
System.out.println(`Quota OK - $Map.of(check.remaining) requests remaining`);
)
import (
"context"
"github.com/ductape/ductape/sdk/go/core"
"github.com/ductape/ductape/sdk/go/ductape"
)
import { FeatureEventTypes, DataTypes } from '@ductape/sdk/types';
auth := core.NewRequestContext("", "", "", "", 'your-access-key')
client, err := client.New(core.EnvProduction, auth)
if err != nil {
return err
}
client.product.init('api-platform');
// Create quota with multiple tiers
client.quota.create({
"name": "Monthly API Requests",
"tag": "monthly-api-quota",
"description": "API request limits per subscription plan",
input: {
userId: { type: DataTypes.STRING },
tier: { type: DataTypes.STRING },
},
"total_quota": 1000000,
"total_init": 1000000,
options: [
{
"quota": 1000, // "Hobby": 1K/month
"uses": 0,
type: FeatureEventTypes.ACTION,
"event": "check-tier",
"app": "quota-service",
input: { "tier": "hobby" },
output: { "allowed": "$Response{allowed}" },
"retries": 2,
},
{
"quota": 10000, // "Starter": 10K/month
"uses": 0,
type: FeatureEventTypes.ACTION,
"event": "check-tier",
"app": "quota-service",
input: { "tier": "starter" },
output: { "allowed": "$Response{allowed}" },
"retries": 2,
},
{
"quota": 100000, // "Pro": 100K/month
"uses": 0,
type: FeatureEventTypes.ACTION,
"event": "check-tier",
"app": "quota-service",
input: { "tier": "pro" },
output: { "allowed": "$Response{allowed}" },
"retries": 2,
},
],
});
// Run quota check
check := client.quota.run({
"tag": "monthly-api-quota",
input: {
"userId": "user123",
"tier": "starter",
},
});
if (check.exceeded) {
fmt.Println('API quota exceeded - upgrade required');
} else {
fmt.Println(`Quota OK - ${check.remaining} requests remaining`);
}
using Ductape.Sdk;
using Ductape.Sdk.Core;
import { FeatureEventTypes, DataTypes } from '@ductape/sdk/types';
var auth = new RequestContext(null, null, null, null, 'your-access-key', null);
var ductape = new Ductape(EnvType.Production, auth);
await ductape.product.init('api-platform');
// Create quota with multiple tiers
await ductape.quota.create({
["name"] = "Monthly API Requests",
["tag"] = "monthly-api-quota",
["description"] = "API request limits per subscription plan",
input: {
userId: { type: DataTypes.STRING },
tier: { type: DataTypes.STRING },
},
["total_quota"] = 1000000,
["total_init"] = 1000000,
options: [
{
["quota"] = 1000, // ["Hobby"] = 1K/month
["uses"] = 0,
type: FeatureEventTypes.ACTION,
["event"] = "check-tier",
["app"] = "quota-service",
input: { ["tier"] = "hobby" },
output: { ["allowed"] = "$Response{allowed}" },
["retries"] = 2,
},
{
["quota"] = 10000, // ["Starter"] = 10K/month
["uses"] = 0,
type: FeatureEventTypes.ACTION,
["event"] = "check-tier",
["app"] = "quota-service",
input: { ["tier"] = "starter" },
output: { ["allowed"] = "$Response{allowed}" },
["retries"] = 2,
},
{
["quota"] = 100000, // ["Pro"] = 100K/month
["uses"] = 0,
type: FeatureEventTypes.ACTION,
["event"] = "check-tier",
["app"] = "quota-service",
input: { ["tier"] = "pro" },
output: { ["allowed"] = "$Response{allowed}" },
["retries"] = 2,
},
],
});
// Run quota check
var check = await ductape.quota.run({
["tag"] = "monthly-api-quota",
input: {
["userId"] = "user123",
["tier"] = "starter",
},
});
if (check.exceeded) {
Console.WriteLine('API quota exceeded - upgrade required');
} else {
Console.WriteLine(`Quota OK - ${check.remaining} requests remaining`);
}
Best Practices
- Define clear quota limits based on your product tiers
- Use meaningful tier names in quota options
- Monitor quota usage to detect abuse or upgrade opportunities
- Set appropriate retry counts for quota checks
- Cache quota checks when possible to reduce overhead
- Reset quota counters periodically (daily, monthly, etc.)
- Provide clear feedback to users when quotas are exceeded
- Use quotas in combination with features for automated limit enforcement