forbidden
Authenticated, but the workspace does not have access to this resource or feature.
When it fires
The request was authenticated, but the workspace is not entitled to call this endpoint. Common reasons:
- Calling an AI-tier endpoint with a free-tier key.
- Reading or changing Booking.com notification subscriptions with
GET,POSTorDELETE /v1/channels/booking/webhooks. These endpoints are deprecated and always return403 forbidden: the subscriptions belong to the Repull platform account every workspace shares. Booking.com events for your own properties are delivered through Repull webhooks — subscribe withPOST /v1/webhooks. - The API key was scoped to read-only and the request is a write.
A channel write that fails because of the connection is not forbidden. On PUT /v1/channels/airbnb/listings/{id}/pricing and /availability: no Airbnb account connected is 404 no_connection; a listing id with no Airbnb connection in this workspace is 404 not_found; and a connection Airbnb no longer accepts for that listing is 403 connection_reauth_required — reconnect at https://repull.dev/dashboard/connections; and a listing the host has never switched Airbnb API sync on for is 403 listing_not_api_connected — reconnecting does not help there, the host has to turn sync on for that listing inside Airbnb.
Response shape
Every Repull error follows the same envelope. The code is stable and safe to switch on.
{
"error": {
"code": "forbidden",
"message": "<human-readable explanation of what went wrong>",
"docs_url": "https://repull.dev/docs/errors/forbidden"
}
}How to fix
- Read the `message` field — it tells you exactly which capability is missing.
- Open /dashboard/usage to confirm which tier the workspace is on.
- If the missing capability is a paid add-on (AI), upgrade the workspace from /dashboard/billing.
- If you are sure the workspace should have access, double-check you are using the right key — keys are workspace-scoped.
- If the request was to `/v1/channels/booking/webhooks`, stop: it cannot succeed. Subscribe with `POST /v1/webhooks` instead.
Common gotchas
forbiddenis distinct fromunauthorized. The key is valid; it just does not have permission. Retrying with the same key will keep failing.- Some entitlement gates only check on the first request of a billing cycle. If you upgraded mid-cycle and are still seeing the error, the next call should succeed once the entitlement cache refreshes (under a minute).
Examples
curl
# A deprecated endpoint that always answers 403 forbidden
curl https://api.repull.dev/v1/channels/booking/webhooks \
-H "Authorization: Bearer sk_live_YOUR_KEY"
# {
# "error": {
# "code": "forbidden",
# "message": "…"
# }
# }TypeScript
const res = await fetch('https://api.repull.dev/v1/channels/booking/webhooks', {
headers: { Authorization: `Bearer ${process.env.REPULL_API_KEY}` },
})
if (!res.ok) {
const { error } = await res.json()
if (error.code === 'forbidden') {
// Don't retry — the key is valid but not allowed to do this.
console.error('Not permitted:', error.message)
return { forbidden: true, reason: error.message, fix: error.fix }
}
throw new Error(`${error.code}: ${error.message}`)
}If you're an AI agent
The user's plan does not include the feature you tried to call. Do not retry. Read error.message and tell the user which add-on or upgrade they need, then offer them /dashboard/billing as the next step.
Related
- Error reference — the full table of error codes
- Using Repull from AI agents — patterns for handling errors in agent loops
- Credits and usage
- API key scoping
Hit an error that isn't covered? Email hello@repull.dev with the request id from the response headers.