Thrysha API

API Docs

Overview

Overview

Quota API lets you enforce per-resource quotas with simple HTTP APIs.

Use this API to register resources, attach quota rules, and then check or consume usage. Typical use cases include daily API call limits, monthly credit balances, or per-tenant rate limits.

v1

Environment & Base URL

Base URL

Use this URL for all API requests: https://quota-api.thrysha.io.

v1

Authentication

Authentication

Every request must send its API key in the Authorization header.

API keys are required for every endpoint. Keep them server-side only, rotate them regularly, and scope them per environment. Requests with missing or invalid keys are rejected before any work is done.

v1
HTTP Request
Authorization: Bearer <API_KEY>
Content-Type: application/json

Core Concepts

Core Concepts

How resources, rules, and enforcement fit together.

• Resource – A logical thing being limited (e.g., “Payments API calls”, “SMS sends”, “team seats”). • Quota rule – Policy attached to a resource that defines how much usage is allowed and when it resets. • quota_policy – "limited" enforces a hard cap; "unlimited" only tracks usage. • enforcement_mode – "enforced" blocks over-limit usage; "observe" records usage but always allows. • reset_strategy – includes unit (hour/day/week/month/year/never) and interval (>0, ignored for never) to control resets. • idempotency – request_id ensures retries don't double-charge or double-consume.

v1

Quickstart Example

Quickstart: Daily limit on discarded apples

A concrete example of capping a domain-specific action with quotas.

Suppose you want to limit how many apples can be discarded each day. Create a resource that represents the discard action, attach a limited fixed-window rule that resets daily, then check or consume against it. This pattern generalizes to “per day”, “per month”, or “lifetime” limits.

v1
HTTP Request
1) POST /v1/resources
      → create "apples-discard"

2) POST /v1/quota-rules
      → quota_policy=limited
      → quota_limit=100
      → reset_strategy={ unit: "day", interval: 1 }
      → enforcement_mode=enforced

3) POST /v1/quota/check
      → preflight a discard (amount=1 or 0)

4) POST /v1/quota/consume
      → record a discard (amount=1) with request_id for idempotency

Use reset_strategy { unit: "day", interval: 1 }; set enforcement_mode=enforced to block over-limit discards.

Resources API

Create Resource

Define a resource that quota rules attach to.

Use this to register a billable or rate-limited entity (API, feature, or customer-facing action). Each resource should be stable and unique so usage and limits stay aligned over time.

v1
HTTP Request
POST /v1/resources

{
  "name": "Payments API",
  "description": "Used by service A"
}
Response
{
  "id": "res_abcd1234",
  "account_id": "acct_123",
  "name": "Payments API",
  "description": "Used by service A",
  "created_at": "2025-01-10T12:34:56Z"
}
Business Rules
  • name is required, trimmed, and must be unique per account (case-insensitive).
  • Resources belong to the caller's account; account_id cannot be overridden.
  • Each account can create up to 100,000 resources (ERR_RESOURCE_LIMIT_REACHED when exceeded).
  • Use stable identifiers; rename is preferred over delete/recreate.
Errors
  • 401 UnauthorizedMissing or invalid API key.
  • 400 Bad RequestInvalid payload (e.g., missing "name", empty after trim).
  • 409 ConflictA resource with the same name already exists for this account.
  • ERR_RESOURCE_LIMIT_REACHEDAccount has reached the maximum number of resources (100,000).
Sample code
const res = await fetch("https://quota-api.thrysha.io/v1/resources", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <API_KEY>",
  },
  body: JSON.stringify({ name: "Payments API", description: "Used by service A" }),
});
const data = await res.json();

List Resources

Fetch all resources for the authenticated account.

Enumerate resources to audit what is being metered, surface IDs for automation, and reconcile against your product catalog.

v1
HTTP Request
GET /v1/resources?page=1&page_size=50
Response
{
  "items": [
    {
      "id": "res_abcd1234",
      "account_id": "acct_123",
      "name": "Payments API",
      "created_at": "..."
    }
  ],
  "page": 1,
  "page_size": 50,
  "total": 1
}
Business Rules
  • Results are scoped to the authenticated account.
  • page defaults to 1 (must be ≥ 1); page_size defaults to 50 and is capped at 200.
Errors
  • 401 UnauthorizedMissing or invalid API key.
  • 400 Bad RequestInvalid page or page_size.
Sample code
const res = await fetch("https://quota-api.thrysha.io/v1/resources?page=1&page_size=50", {
  headers: {
    "Authorization": "Bearer <API_KEY>",
  },
});
const data = await res.json();

Delete Resource

Remove a resource by ID.

Use for cleanup when a resource is retired. Deleting removes it from future listings; ensure you have no active rules or dependencies before deleting.

v1
HTTP Request
DELETE /v1/resources/{resourceID}
Response
{ "status": "deleted" }
Business Rules
  • Resource must belong to the authenticated account.
Errors
  • 401 UnauthorizedMissing or invalid API key.
  • 404 Not FoundNo resource with this ID for the account.
Sample code
await fetch("https://quota-api.thrysha.io/v1/resources/res_abcd1234", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer <API_KEY>",
  },
});

Quota Rules API

Create Quota Rule

Attach quota policy, limits, and reset strategy to a resource.

Define how usage is tracked: limited rules enforce caps and require quota_limit + enforcement_mode; unlimited rules observe usage without blocking. reset_strategy now takes unit (hour/day/week/month/year/never) and interval (>0, ignored for never).

v1
HTTP Request
POST /v1/quota-rules

{
  "resource_id": "res_abcd1234",
  "quota_limit": 1000,
  "quota_policy": "limited",              // optional, defaults to "limited"
  "reset_strategy": {
    "unit": "hour",                       // hour | day | week | month | year | never
    "interval": 1                         // > 0; ignored for "never"
  },
  "enforcement_mode": "enforced"          // or "non_enforced"
}
Response
{
  "id": "qr_123",
  "resource_id": "res_abcd1234",
  "quota_policy": "limited",
  "quota_limit": 1000,
  "reset_strategy": { "unit": "hour", "interval": 1 },
  "enforcement_mode": "enforced",
  "created_at": "..."
}
Business Rules
  • resource_id must belong to the authenticated account; only one active quota rule may exist per resource.
  • quota_policy defaults to limited. For monitoring-only set unlimited (supply quota_limit even though it will not gate requests).
  • quota_limit must be a positive integer.
  • reset_strategy.unit supports hour/day/week/month/year/never; interval must be > 0 (ignored for never).
  • enforcement_mode can be enforced or non_enforced.
  • Creating a rule for a resource that already has one returns ERR_CREATE_QUOTA_RULE_FAILED.
Errors
  • 401 UnauthorizedMissing or invalid API key.
  • 400 Bad RequestInvalid combination of fields or quota_limit <= 0.
  • 404 Not Foundresource_id does not exist or is not owned by this account.
  • ERR_CREATE_QUOTA_RULE_FAILEDA quota rule already exists for this resource.
Sample code
await fetch("https://quota-api.thrysha.io/v1/quota-rules", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <API_KEY>",
  },
  body: JSON.stringify({
    resource_id: "res_abcd1234",
    quota_policy: "limited",
    quota_limit: 1000,
    reset_strategy: { unit: "hour", interval: 1 },
    enforcement_mode: "enforced",
  }),
});

List Quota Rules

Get quota rules for a resource.

Inspect current limits and reset strategies for a resource. Useful for dashboards, audits, and ensuring clients see active enforcement settings.

v1
HTTP Request
GET /v1/quota-rules?resource_id=res_abcd1234&page=1&page_size=50
Response
{
  "items": [
    {
      "id": "qr_123",
      "resource_id": "res_abcd1234",
      "quota_limit": 1000,
      "quota_policy": "limited",
      "reset_strategy": "fixed_window",
      "reset_interval_seconds": 3600,
      "enforcement_mode": "enforced",
      "created_at": "..."
    }
  ],
  "page": 1,
  "page_size": 50,
  "total": 1
}
Business Rules
  • resource_id is required.
  • page defaults to 1 (must be ≥ 1); page_size defaults to 50 and is capped at 200.
Errors
  • 401 UnauthorizedMissing or invalid API key.
  • 404 Not Foundresource_id does not exist or is not owned by this account.
  • 400 Bad RequestInvalid page or page_size.
Sample code
const res = await fetch("https://quota-api.thrysha.io/v1/quota-rules?resource_id=res_abcd1234&page=1&page_size=50", {
  headers: {
    "Authorization": "Bearer <API_KEY>",
  },
});
const data = await res.json();

Delete Quota Rule

Remove a quota rule by ID.

Stop enforcing or observing usage for a resource. Ensure you create a replacement rule if the resource still needs coverage.

v1
HTTP Request
DELETE /v1/quota-rules/{ruleID}
Response
{ "status": "deleted" }
Business Rules
  • Only one rule per resource; deleting removes enforcement entirely.
Errors
  • 401 UnauthorizedMissing or invalid API key.
  • 404 Not FoundNo quota rule with this ID for the account.
Sample code
await fetch("https://quota-api.thrysha.io/v1/quota-rules/qr_123", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer <API_KEY>",
  },
});

Quota Evaluation API

Check Quota

Check usage without consuming it (amount can be 0).

Preflight requests to see if they would be allowed. No counters are consumed. Ideal for client gating and showing remaining balances before acting.

v1
HTTP Request
POST /v1/quota/check

{
  "resource_id": "res_abcd1234",
  "subject_id": "sub_1234",
  "amount": 0
}
Response
{
  "allowed": true,
  "remaining": 975,
  "limit": 1000
}
Business Rules
  • subject_id scopes usage per subject (user/tenant); include it for every check.
  • amount must be >= 0; use amount=0 for a read-only peek.
  • Resource must already have a quota rule, otherwise ERR_NO_QUOTA_RULE.
  • For non_enforced rules, response is always allowed=true but still reports remaining/limit.
Errors
  • 401 UnauthorizedMissing or invalid API key.
  • 404 Not Foundresource_id does not exist or is not owned by this account.
  • ERR_NO_QUOTA_RULENo quota rule configured for the resource.
  • 400 Bad RequestInvalid payload (e.g., negative amount).
Sample code
const res = await fetch("https://quota-api.thrysha.io/v1/quota/check", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <API_KEY>",
  },
  body: JSON.stringify({ resource_id: "res_abcd1234", subject_id: "sub_1234", amount: 0 }),
});
const data = await res.json();

Consume Quota

Consume usage with an idempotent request_id.

Use this to record usage and enforce limits. Provide a stable request_id to avoid double-charging on retries. Enforced rules block when limits are exceeded; observe rules only log usage.

v1
HTTP Request
POST /v1/quota/consume

{
  "resource_id": "res_abcd1234",
  "subject_id": "sub_1234",
  "amount": 25,
  "request_id": "unique-idempotency-key"
}
Response
{
  "allowed": true,
  "remaining": 950
}
Business Rules
  • subject_id scopes usage per subject (user/tenant); include it for every consume.
  • amount must be > 0 (ERR_INVALID_AMOUNT otherwise).
  • Provide a stable request_id per idempotent action; replays return the prior decision.
  • non_enforced rules never block; enforced rules return ERR_QUOTA_CONSUME_FAILED / ERR_QUOTA_EXCEEDED when limits are exceeded.
  • Fails with ERR_NO_QUOTA_RULE if the resource has no rule.
Errors
  • 401 UnauthorizedMissing or invalid API key.
  • 404 Not Foundresource_id does not exist or is not owned by this account.
  • ERR_NO_QUOTA_RULENo rule is configured for this resource.
  • ERR_INVALID_AMOUNTamount must be greater than 0.
  • ERR_QUOTA_EXCEEDEDThe consumption would exceed the limit (enforced rules only).
  • ERR_QUOTA_CONSUME_FAILEDQuota cannot be consumed (generic failure).
  • 409 Conflictrequest_id already used with different parameters.
Sample code
const res = await fetch("https://quota-api.thrysha.io/v1/quota/consume", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer <API_KEY>",
  },
  body: JSON.stringify({
    resource_id: "res_abcd1234",
    subject_id: "sub_1234",
    amount: 25,
    request_id: "unique-idempotency-key",
  }),
});
const data = await res.json();
Usage Durability Characteristics

Usage increments are stored in memory and flushed periodically. In rare failure scenarios (e.g., Redis process crash), increments from the last few minutes may not be persisted.

This affects reporting accuracy for the most recent window but does not affect quota enforcement, which always uses the live counter state at the moment of the request.