Plans and features
What your organisation's plan decides, what feature_unavailable means, how fat webhooks fall back to thin, and how long the change feed and delivery log reach back.
Your organisation's plan decides what it can use. The API applies it as it answers, so a request the plan does not cover gets a clear answer instead of a silent difference.
| The plan sets | Where it shows |
|---|---|
| Features | Requests that need one answer 403 feature_unavailable without it. See Features. |
| Rate tier | Your request budgets. See Rate limits. |
| Monthly quotas | GET /v1/usage, and 429 quota_exceeded once one is spent. See Usage and quotas. |
| Retention | How far back the change feed and the webhook delivery log reach. See Retention. |
| Seats and API keys | Inviting a member or creating a key beyond the plan's number is refused with 403 plan_limit_reached. |
| Catalogue licences | Which network catalogues, and which of their fields, you can see. See Licences. |
An organisation is given its plan shortly after it is created; until then, nothing is limited. When the plan changes, the API applies the new one within moments. Plans are not on sale yet: billing is switched off, so your plan is the one FurniOps assigned.
Features
| Feature | What it switches on | Without it |
|---|---|---|
bulk_exports | Bulk exports of the catalogue. | POST /v1/exports answers feature_unavailable. |
fat_webhooks | Webhook endpoints with payload: "fat", whose events carry the full object. | Creating an endpoint with a fat payload, or switching one to it, answers feature_unavailable. An endpoint that is already fat is sent thin events (below). |
restricted_keys | Restricted API keys, including every key for an AI agent. | Creating a restricted key answers feature_unavailable; the dashboard's key wizard offers secret keys only. |
sso | Single sign-on for your members. | Connecting an identity provider answers feature_unavailable; the dashboard shows SSO as included in higher plans. |
mcp | The MCP server. | Every MCP request for the organisation answers 403 feature_unavailable. |
ai_agents | The AI agents examining your sources and proposing changes. | The agents ask nothing about your catalogue and make no proposals. The dashboard shows Proposals and Settings › AI agents as included in higher plans. |
feature_unavailable
403 feature_unavailable means the request needs a feature your plan does not include. Nothing
was changed, and the same request gets the same answer until the plan changes, so do not retry
it. Leave the feature out (a thin endpoint, paging GET /v1/products instead of an export), or
move to a plan that includes it.
{
"type": "https://docs.furniops.com/errors/feature_unavailable",
"title": "Not included in the plan",
"status": 403,
"code": "feature_unavailable",
"detail": "Bulk exports are not included in the plan",
"request_id": "req_034XqBaL2mRLTZPXyRbaUq",
"doc_url": "https://docs.furniops.com/errors/feature_unavailable"
}The SDK throws it as a PermissionError with code: "feature_unavailable".
Fat webhooks fall back to thin
A fat payload is a webhook endpoint's setting. When your plan loses fat webhooks, FurniOps keeps your endpoints working rather than turning them off:
- An endpoint that is already
fatkeeps its setting and stays editable: you can change its URL, event types or filters as before. - Its events are sent thin while the plan lacks the feature:
datacarries what changed, but noobject. - When the feature comes back, the same endpoints are sent fat events again, with nothing to change on your side.
So a receiver that handles fat events should also handle an event without data.object: apply
data.fields, or read the object back. The handler in
Sync a catalogue already does. The change feed's and
the stream's payload=fat parameter is not a plan feature.
Retention
Your plan sets how many days back two logs reach, never more than the service keeps:
| Log | Service keeps | With fewer plan days |
|---|---|---|
| The change feed and the stream | 30 days | A cursor at an event older than the plan's days answers 400 invalid_request on cursor, as an expired cursor does. Start again from GET /v1/products (with updated_since), then follow the feed without a cursor. |
| The webhook delivery log | 30 days | Listing, reading and resending deliveries reach back only the plan's days; an older delivery is not listed and answers 404. A recovery of failed deliveries is limited to the plan's days. |
A plan's days hide older entries; they do not delete them. If the plan later keeps more days, entries still within the service's 30 days show again.