Skip to content

This is the staging environment's documentation. It is a draft and may change at any time.

Get the organization's subscription

GET
/orgs/{orgId}/subscription
curl --request GET \
--url https://api-staging.fedwright.com/v1/orgs/019aa3f2-6d10-7b20-9c4f-7e2d3cad5b12/subscription \
--header 'Authorization: Bearer <token>'

The plan the organization is on and where it came from, when the plan ends or renews, and how much of each quota has been used: direct API requests, MCP prompts, and premium units. A figure that can’t be read right now is left out of usage, and the others are still shown. Only owners can read it, and only from Fedwright’s own web and mobile apps; analysts and reviewers get 403 (insufficient-role), and machine clients and MCP clients are refused. It needs no active subscription, so an owner can always see where the organization stands.

orgId
required

A UUIDv7.

string format: uuid

The organization. The caller must be a member; otherwise the response is 404, as if it didn’t exist.

The subscription.

Media typeapplication/json

The plan an organization is on. After a plan ends, whether a grant, a cancelled subscription, or a payment that kept failing, the organization stays active on free with its data, and lapsedAt says when.

object
cancelAtPeriodEnd
required

Whether the subscription ends at the end of the paid period.

boolean
currentPeriodEnd
required

The end of the period already paid for. Null unless the owner pays.

null | string format: date-time
endsAt
required

When the plan stops being in force and the organization falls back to free: a grant’s end, or the end of the grace period after a failed payment. Null when nothing ends it.

null | string format: date-time
entitlements
required

What a plan includes besides its API quotas.

object
alertSubscriptions
required

How many saved searches the organization can alert on.

integer
>= 1
enrichedData
required

Whether the plan includes Fedwright’s enriched data.

boolean
mcp
required

What AI assistants connected through MCP may ask, counted in prompts.

object
perDay
required

How many prompts AI assistants connected through MCP may send per day.

integer
>= 1
perMonth
required

Null means 30 times the daily number.

null | integer
>= 1
premium
required

Premium operations per day, for the whole organization. 0 means none. Null while the plan’s number is not set.

null | integer
seats
required

How many people can be members.

integer
>= 1
slaPercent
required

The availability Fedwright promises, in percent. Null for no promise.

null | number
support
required

The support level: community, email, or email-slack.

string
Allowed values: community email email-slack
lapsedAt
required

When the organization fell back to free from a plan that ended. Null if it has not.

null | string format: date-time
pastDueSince
required

When the first failed payment of the current run happened. Null when payments are fine.

null | string format: date-time
quotas
required

What an organization may send to the API, counted for the whole organization. burst counts in the plan’s burst window, daily in the UTC calendar day, and monthly in the UTC calendar month. The numbers are the ones this environment enforces.

object
burst
required

The number of requests allowed in the burst window.

integer
>= 1
daily
required

The number of requests allowed in a UTC calendar day.

integer
>= 1
monthly
required

The number of requests allowed in a UTC calendar month.

integer
>= 1
source
required

Where the plan comes from: provider (the owner pays), grant (given by Fedwright for a set time), or free (the plan every organization starts on).

string
Allowed values: free grant provider
status
required

active on every plan, free included. inactive only when the payment provider reports a status Fedwright doesn’t know.

string
Allowed values: active inactive
tier
required

A plan’s tier, from the smallest to the largest.

string
Allowed values: free small medium large
updatedAt
required

When the plan or its status last changed.

string format: date-time
usage

What the organization has used of each quota. A figure that can’t be read right now is left out, and the others are still shown. Direct API use is counted for the whole organization; MCP prompts have their own counts.

object
apiDay

How much of one quota has been used in its current window.

object
limit
required

The most the organization may use in the window.

integer
resetsAt
required

When the count starts again at 0.

string format: date-time
used
required

How much the organization has used in the current window.

integer
apiMonth

How much of one quota has been used in its current window.

object
limit
required

The most the organization may use in the window.

integer
resetsAt
required

When the count starts again at 0.

string format: date-time
used
required

How much the organization has used in the current window.

integer
mcpDay

How much of one quota has been used in its current window.

object
limit
required

The most the organization may use in the window.

integer
resetsAt
required

When the count starts again at 0.

string format: date-time
used
required

How much the organization has used in the current window.

integer
mcpMonth

How much of one quota has been used in its current window.

object
limit
required

The most the organization may use in the window.

integer
resetsAt
required

When the count starts again at 0.

string format: date-time
used
required

How much the organization has used in the current window.

integer
premiumDay

How much of one quota has been used in its current window.

object
limit
required

The most the organization may use in the window.

integer
resetsAt
required

When the count starts again at 0.

string format: date-time
used
required

How much the organization has used in the current window.

integer

Examples

Exampledefault

A subscription summary

{
"cancelAtPeriodEnd": false,
"currentPeriodEnd": "2026-12-01T15:31:00Z",
"endsAt": null,
"entitlements": {
"alertSubscriptions": 5,
"enrichedData": true,
"mcp": {
"perDay": 100,
"perMonth": null
},
"premium": 10,
"seats": 5,
"slaPercent": null,
"support": "email"
},
"lapsedAt": null,
"pastDueSince": null,
"quotas": {
"burst": 60,
"daily": 2000,
"monthly": 40000
},
"source": "provider",
"status": "active",
"tier": "small",
"updatedAt": "2026-11-01T15:31:00Z",
"usage": {
"apiDay": {
"limit": 2000,
"resetsAt": "2026-11-07T00:00:00Z",
"used": 412
}
}
}

The access token is missing, expired, or invalid.

Media typeapplication/problem+json

RFC 9457 Problem Details.

object
detail

An explanation specific to this occurrence of the problem. It is absent for server errors.

string
errors

Validation errors, by field path.

object
key
additional properties
Array<string>
instance

A URI reference that identifies this occurrence of the problem, when the API provides one.

string
limit

On rate-limited, the quota that is used up, such as org-day. On premium-quota-exceeded, org-premium-day. A 429 with an empty body does not name it.

string
resetsAt

On rate-limited from the API and on premium-quota-exceeded, when that quota starts again.

string format: date-time
status
required

The HTTP status code of the response, from 400 to 599.

integer
>= 400 <= 599
title
required

A short, human-readable summary of the problem. Use type to identify the kind of problem, not this text.

string
traceId
required

W3C trace ID of the failed request.

string
type
required

https://fedwright.com/problems/{code}, the same in every environment.

string format: uri

Example generated

{
"detail": "example",
"errors": {
"additionalProperty": [
"example"
]
},
"instance": "example",
"limit": "example",
"resetsAt": "2026-04-15T12:00:00Z",
"status": 1,
"title": "example",
"traceId": "example",
"type": "https://example.com"
}

The Problem type says which check refused the caller, when that is about the caller’s own token, client, or role: insufficient-scope when the token’s scopes (or an MCP grant’s) lack the operation’s scope, with WWW-Authenticate: Bearer error="insufficient_scope", scope="..." (RFC 6750) naming the missing scopes; client-not-allowed when the operation doesn’t admit the caller’s kind of client, such as a machine client calling a user-only operation; and insufficient-role when a confirmed member’s roles don’t allow the action. Any other refusal is the generic forbidden, which says nothing more. Another organization’s resource is 404 (not-found) instead, so no reason confirms that it exists. An owner or administrator who sent no proof of a second factor gets mfa-required. An operation that needs an active subscription, when the organization has none, returns subscription-inactive, or organization-suspended when Fedwright suspended the organization. A suspended organization also refuses invitations, new joins through an invitation, and role changes with organization-suspended. Creating or joining an organization without a verified email returns email-unverified, and accepting an invitation sent to another address returns invitation-email-mismatch. A request from Fedwright’s web or mobile app whose session acts for no organization yet returns organization-required, except on getMe, createOrganization, and acceptInvitation. Shared data needs the acting organization’s own subscription; another organization’s doesn’t count.

Media typeapplication/problem+json

RFC 9457 Problem Details.

object
detail

An explanation specific to this occurrence of the problem. It is absent for server errors.

string
errors

Validation errors, by field path.

object
key
additional properties
Array<string>
instance

A URI reference that identifies this occurrence of the problem, when the API provides one.

string
limit

On rate-limited, the quota that is used up, such as org-day. On premium-quota-exceeded, org-premium-day. A 429 with an empty body does not name it.

string
resetsAt

On rate-limited from the API and on premium-quota-exceeded, when that quota starts again.

string format: date-time
status
required

The HTTP status code of the response, from 400 to 599.

integer
>= 400 <= 599
title
required

A short, human-readable summary of the problem. Use type to identify the kind of problem, not this text.

string
traceId
required

W3C trace ID of the failed request.

string
type
required

https://fedwright.com/problems/{code}, the same in every environment.

string format: uri

Example generated

{
"detail": "example",
"errors": {
"additionalProperty": [
"example"
]
},
"instance": "example",
"limit": "example",
"resetsAt": "2026-04-15T12:00:00Z",
"status": 1,
"title": "example",
"traceId": "example",
"type": "https://example.com"
}

The resource does not exist, or belongs to another organization.

Media typeapplication/problem+json

RFC 9457 Problem Details.

object
detail

An explanation specific to this occurrence of the problem. It is absent for server errors.

string
errors

Validation errors, by field path.

object
key
additional properties
Array<string>
instance

A URI reference that identifies this occurrence of the problem, when the API provides one.

string
limit

On rate-limited, the quota that is used up, such as org-day. On premium-quota-exceeded, org-premium-day. A 429 with an empty body does not name it.

string
resetsAt

On rate-limited from the API and on premium-quota-exceeded, when that quota starts again.

string format: date-time
status
required

The HTTP status code of the response, from 400 to 599.

integer
>= 400 <= 599
title
required

A short, human-readable summary of the problem. Use type to identify the kind of problem, not this text.

string
traceId
required

W3C trace ID of the failed request.

string
type
required

https://fedwright.com/problems/{code}, the same in every environment.

string format: uri

Example generated

{
"detail": "example",
"errors": {
"additionalProperty": [
"example"
]
},
"instance": "example",
"limit": "example",
"resetsAt": "2026-04-15T12:00:00Z",
"status": 1,
"title": "example",
"traceId": "example",
"type": "https://example.com"
}

A rate limit is used up. Direct API access counts against the organization’s burst, daily, and monthly quotas, which all its machine clients share; there is no client quota. A 429 comes in two shapes with two header families, so read the response by what it carries.

A machine client’s calls can get a 429 with an empty body. It has three headers: X-RateLimit-Limit, the exhausted rule’s limit and window, such as 3000, 3000;w=2592000; X-RateLimit-Remaining, what is left in that window (0 on a 429); and X-RateLimit-Reset, the seconds until that window resets. It has no Retry-After, no RateLimit headers, no Problem, and does not name the quota. Read the quota from the window w:

w (seconds) Quota
60 Burst.
86400 Daily.
2592000 Monthly (the calendar month is reported as 30 days; X-RateLimit-Reset is exact).

Wait X-RateLimit-Reset seconds before you retry. Refused requests still count: a client that keeps calling after a 429 keeps adding to the counter, so it does not regain budget inside the window. A tier change takes effect within 10 minutes (checkout, the billing portal, and grants alike), once the client gets a new access token.

Every other 429 has a Problem and Retry-After. The Problem type is rate-limited for a used-up quota, or, for an ask, ai-budget-exceeded or premium-quota-exceeded (below). On rate-limited, Retry-After is the seconds until the used-up limit’s window resets, the latest if several are. The Problem also carries limit, the quota that is used up (the one that resets last, if several are), resetsAt, when it starts again, and traceId. RateLimit-Policy and RateLimit describe only the caller’s own limits, here and on every other response a limit applies to. A request refused with rate-limited uses no quota. One refused after that check, for its scope, role, subscription, or kind of client, still counts, so once a quota is used up such a request gets 429 instead of its 403. A request that fails authentication is not counted. An ask that the organization’s AI spending budget can’t cover returns ai-budget-exceeded instead, with Retry-After at the end of the budget’s window: that budget counts what asks cost, not how many there are. An ask that the organization’s premium units for the day can’t cover returns premium-quota-exceeded, with limit (org-premium-day), resetsAt (the next midnight UTC), and Retry-After. That is the plan’s allowance: a plan with no premium units never covers an ask, and a higher plan may. A refused ask uses no units.

Media typeapplication/problem+json

RFC 9457 Problem Details.

object
detail

An explanation specific to this occurrence of the problem. It is absent for server errors.

string
errors

Validation errors, by field path.

object
key
additional properties
Array<string>
instance

A URI reference that identifies this occurrence of the problem, when the API provides one.

string
limit

On rate-limited, the quota that is used up, such as org-day. On premium-quota-exceeded, org-premium-day. A 429 with an empty body does not name it.

string
resetsAt

On rate-limited from the API and on premium-quota-exceeded, when that quota starts again.

string format: date-time
status
required

The HTTP status code of the response, from 400 to 599.

integer
>= 400 <= 599
title
required

A short, human-readable summary of the problem. Use type to identify the kind of problem, not this text.

string
traceId
required

W3C trace ID of the failed request.

string
type
required

https://fedwright.com/problems/{code}, the same in every environment.

string format: uri

Examples

An ask the premium units can't cover

{
"limit": "org-premium-day",
"resetsAt": "2026-11-08T00:00:00Z",
"status": 429,
"title": "Too Many Requests",
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"type": "https://fedwright.com/problems/premium-quota-exceeded"
}
RateLimit
string

For each limit in RateLimit-Policy, the requests r its window still allows and the seconds t until the window resets, such as "org-burst";r=7;t=40, "org-day";r=62;t=41000.

RateLimit-Policy
string

The caller’s rate limits, in the IETF HTTPAPI RateLimit header fields: each limit’s name, its quota q, and its window w in seconds, such as "org-burst";q=20;w=60, "org-day";q=100;w=86400.

Retry-After
integer

Seconds to wait before retrying.

X-RateLimit-Limit
string

On a 429 with an empty body (and on the successful responses that carry these headers), the exhausted rule’s limit and window w in seconds, such as 3000, 3000;w=2592000. The window names the quota: 60 is burst, 86400 is daily, and 2592000 is monthly.

X-RateLimit-Remaining
integer

What is left in that rule’s window (0 on a 429).

X-RateLimit-Reset
integer

Seconds until that rule’s window resets.

Any other error. A request body over 64 KiB returns 413 (payload-too-large), and a request that takes longer than 10 seconds (90 for askOpportunities) returns 503 (request-timeout). An invitation when the API can’t send mail returns 503 (mail-unavailable), and creates nothing. An unexpected failure returns 500 (internal-error) with only type, title, status, and traceId.

Media typeapplication/problem+json

RFC 9457 Problem Details.

object
detail

An explanation specific to this occurrence of the problem. It is absent for server errors.

string
errors

Validation errors, by field path.

object
key
additional properties
Array<string>
instance

A URI reference that identifies this occurrence of the problem, when the API provides one.

string
limit

On rate-limited, the quota that is used up, such as org-day. On premium-quota-exceeded, org-premium-day. A 429 with an empty body does not name it.

string
resetsAt

On rate-limited from the API and on premium-quota-exceeded, when that quota starts again.

string format: date-time
status
required

The HTTP status code of the response, from 400 to 599.

integer
>= 400 <= 599
title
required

A short, human-readable summary of the problem. Use type to identify the kind of problem, not this text.

string
traceId
required

W3C trace ID of the failed request.

string
type
required

https://fedwright.com/problems/{code}, the same in every environment.

string format: uri

Example generated

{
"detail": "example",
"errors": {
"additionalProperty": [
"example"
]
},
"instance": "example",
"limit": "example",
"resetsAt": "2026-04-15T12:00:00Z",
"status": 1,
"title": "example",
"traceId": "example",
"type": "https://example.com"
}