For AI agents: markdown of this page — /docs-content-en/infra/access-tokens/resource-url.md documentation index — /llms.txt
Signed resource URL
POST /v1/infra/servers/:id/access-tokens/:tokenId/resource-url
Issues a GET/HEAD URL for one resource of a private application: CSS, an image or a font. It works without a browser Gateway session and does not open other application paths. Anyone possessing the URL can read the selected resource until expiry or parent token revocation. Sign only content you intend to distribute to widget recipients.
Requires the key that manages the server and an existing api-bearer token created by that key through Mint a token, including the required audience approval. No new token record is created; the parent's lifetime and approved audience are not extended. Development-team, external-collaborator and Cowork keys cannot call this operation. Check section availability before calling.
Known link-preview fetchers receive a local card for a public application or a neutral page for a private application; the Gateway does not proxy their request through the tunnel even when it carries a resource URL. A resource URL does not override this policy.
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
Parameterid |
Inpath | Typestring | Requiredyes | DescriptionServer ID from List servers |
ParametertokenId |
Inpath | Typestring | Requiredyes | Descriptiondata.id of an existing minted api-bearer token |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
Fieldpath |
Typestring | Requiredyes | DescriptionAbsolute ASCII path of 2–1024 characters, for example /widget/style.css. The root / is not allowed. Allowed characters: letters, digits, /, ., _, ~, -. No query, fragment, %, // or ./.. segments. /robots.txt, /_gw, /tunnel and every path inside /_gw/ or /tunnel/ are reserved |
FieldttlSeconds |
Typeinteger | Requiredno | Description1–2592000 seconds, default 86400. Actual expiry is capped by the parent |
Extra body fields are rejected with 400 INVALID_RESOURCE_REQUEST.
Examples
Run on your application server. Do not send the key or user session to the browser.
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/access-tokens/TOKEN_ID/resource-url" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"path":"/widget/style.css","ttlSeconds":86400}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/access-tokens/TOKEN_ID/resource-url" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{"path":"/widget/style.css","ttlSeconds":86400}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/access-tokens/TOKEN_ID/resource-url', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ path: '/widget/style.css', ttlSeconds: 86400 }),
})
const result = await res.json()
if (!res.ok || result.success !== true) {
throw new Error(result.error?.code ?? `HTTP_${res.status}`)
}
const { data } = result
// Use data.url in the widget and replace it before data.expiresAt.
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/access-tokens/TOKEN_ID/resource-url', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
Authorization: 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({ path: '/widget/style.css', ttlSeconds: 86400 }),
})
const result = await res.json()
if (!res.ok || result.success !== true) {
throw new Error(result.error?.code ?? `HTTP_${res.status}`)
}
const { data } = result
// Use data.url in the widget and replace it before data.expiresAt.
Response fields
| Field | Type | Description |
|---|---|---|
Fieldsuccess |
Typeboolean | Descriptiontrue |
Fielddata |
Typeobject | DescriptionSigned URL and its expiry |
Fielddata.url |
Typestring | DescriptionResource URL carrying __resource; preserve the entire URL |
Fielddata.expiresAt |
Typestring (ISO 8601) | DescriptionURL expiry, capped by the parent |
Response example
Captured from a local HTTP call; the deployment hostname and credential are masked.
{
"success": true,
"data": {
"url": "https://app-example.vibecode.bitrix24.com/widget/style.css?__resource=SIGNED_RESOURCE_JWT",
"expiresAt": "2026-10-10T14:11:21.000Z"
}
}
Error response example
400 — ttlSeconds is zero:
{
"success": false,
"error": {
"code": "INVALID_RESOURCE_REQUEST",
"message": "Expected path and optional integer ttlSeconds; no extra fields."
}
}
Errors
| HTTP | Code | Action |
|---|---|---|
| HTTP400 | CodeINVALID_RESOURCE_REQUEST |
ActionFix the body, field types or TTL |
| HTTP400 | CodeINVALID_RESOURCE_PATH |
ActionUse a canonical ASCII resource path |
| HTTP400 | CodeWRONG_TOKEN_MODE |
ActionUse an api-bearer parent |
| HTTP400 | CodeSERVER_NO_SUBDOMAIN |
ActionUse a server with a subdomain |
| HTTP401 | CodeMISSING_API_KEY |
ActionNo API key was supplied through X-Api-Key or a supported Authorization: Bearer scheme |
| HTTP401 | CodeINVALID_API_KEY |
ActionThe authentication key is not recognized |
| HTTP401 | CodeKEY_INACTIVE |
ActionThe requesting API key is no longer active |
| HTTP401 | CodeKEY_EXPIRED |
ActionThe requesting API key has expired; this is distinct from resource URL expiry |
| HTTP401 | CodeNO_PORTAL |
ActionA non-management key has no portal binding |
| HTTP401 | CodeCOWORK_CHAT_KEY_INACTIVE |
ActionThe parent device key behind a Cowork chat key is no longer usable |
| HTTP401 | CodeWRONG_AUTH_SCHEME |
ActionAn OAuth application key was sent as a Bearer session: put the key in X-Api-Key and the session in Authorization: Bearer |
| HTTP401 | CodeINVALID_SESSION |
ActionThe supplied OAuth session is invalid or expired |
| HTTP401 | CodeTOKEN_EXPIRED |
ActionThe OAuth user token expired and its refresh failed; re-authorization is required |
| HTTP401 | CodeTOKEN_INVALID |
ActionWhen the partner AI plane is enabled, its supplied token is unknown or expired |
| HTTP401 | CodeKEY_REVOKED |
ActionThe partner credential behind the AI plane token is revoked |
| HTTP402 | CodeACCOUNT_FROZEN |
ActionThe key owner’s account is frozen. With wallet-debt scoping disabled, the shared API-key guard refuses this call before its handler. Follow error.topupUrl to resolve the balance; this status alone does not authorize repeating a prior write. |
| HTTP403 | CodeKEY_BLOCKED |
ActionThe current or a recorded previous token issuer is blocked |
| HTTP403 | CodeTOKEN_OWNER_MISMATCH |
ActionUse the key that owns both parent and server |
| HTTP403 | CodeWRITE_BLOCKED_READONLY_KEY |
ActionA read-only key cannot perform this write. |
| HTTP403 | CodeINFRA_FORBIDDEN_FOR_COWORK_KEY |
ActionUse the key that manages the server outside Cowork |
| HTTP403 | CodePORTAL_COLLABORATOR_KEY_OUT_OF_SCOPE |
ActionA development-team key cannot sign resource URLs |
| HTTP403 | CodeEXTERNAL_COLLABORATOR_KEY_OUT_OF_SCOPE |
ActionAn external-collaborator key cannot sign resource URLs |
| HTTP403 | CodeIP_NOT_ALLOWED |
ActionThe caller IP is outside the key allowlist. |
| HTTP403 | CodeOWNER_BLOCKED |
ActionThe key owner is blocked. |
| HTTP403 | CodeOWNER_DELETED |
ActionThe key owner was deleted. |
| HTTP403 | CodePORTAL_SUSPENDED |
ActionThe bound portal is suspended. |
| HTTP403 | CodePORTAL_DELETED |
ActionThe bound portal was deleted. |
| HTTP403 | CodePORTAL_BLOCKED |
ActionThe bound portal is blocked. |
| HTTP403 | CodeMANAGEMENT_KEY_NO_ENTITY_ACCESS |
ActionThe management key lacks the portal binding or entity authority required by this call. |
| HTTP403 | CodeAGENT_MAINTENANCE_KEY_OUT_OF_SCOPE |
ActionThe maintenance key route list does not include this operation. |
| HTTP403 | CodeAPP_API_KEY_OUT_OF_SCOPE |
ActionThe application key route list does not include this operation. |
| HTTP403 | CodeWAITLIST_PENDING |
ActionThe key owner has not been activated. |
| HTTP403 | CodeSESSION_APP_MISMATCH |
ActionThe OAuth session belongs to another application. |
| HTTP403 | CodePLANE_FORBIDDEN |
ActionThe partner key does not allow this AI plane. |
| HTTP403 | CodeSYSTEM_FORBIDDEN |
ActionThe partner key does not allow this AI system. |
| HTTP403 | CodeSCOPE_FORBIDDEN |
ActionThe partner AI plane forbids this route. |
| HTTP403 | CodeCONNECT_COMPANY_DERIVED_TOKEN_FORBIDDEN |
ActionA company connection key cannot manage derived tokens. |
| HTTP403 | CodeCOWORK_READONLY |
ActionThe Cowork seat is read-only. |
| HTTP403 | CodeGALAXY_DISABLED |
ActionGalaxy operations are disabled for this portal. |
| HTTP404 | CodeNOT_FOUND |
ActionThe parent token was not found or the server's portal has been deactivated |
| HTTP404 | CodeSERVER_NOT_FOUND |
ActionCheck the server ID |
| HTTP410 | CodeALREADY_REVOKED |
ActionMint a new approved parent token |
| HTTP410 | CodeTOKEN_EXPIRED |
ActionMint a new approved parent with a valid expiry |
| HTTP429 | CodeQUOTA_EXCEEDED |
ActionAPI billing is enabled with a nonzero overage price: the daily free quota is exhausted and the PREPAY balance is not positive. Top up the balance. error.quota and error.used report counts; X-RateLimit-Quota, X-RateLimit-Used and X-RateLimit-Remaining report the quota, usage and zero remainder. This refusal does not promise Retry-After or X-RateLimit-Scope |
| HTTP429 | CodeCALLER_RATE_LIMITED |
ActionThe shared key or user request limit. Wait for the number of seconds specified in Retry-After; X-RateLimit-Scope identifies the refusing layer |
| HTTP503 | CodeFEATURE_DISABLED |
ActionThe access-token section is unavailable |
| HTTP503 | CodeACCOUNT_PENDING_ERASURE |
ActionThe key owner is pending erasure or being erased. Header Retry-After: 3600. |
| HTTP503 | CodeSERVICE_DISABLED |
ActionThe partner AI plane or its quota-readiness service is disabled. No Retry-After is promised for this refusal. |
| HTTP503 | Codeuser_self_deletion_pending |
ActionThe API key owner scheduled self-deletion. The token plugin refuses the call before its handler. Header Retry-After: 604800. |
When reading a resource, an altered, expired or revoked URL, another method, query or path returns 401 BH_RESOURCE_URL_INVALID. Resource signatures are not accepted as Bearer or cookie sessions. If the application tunnel is disconnected, the Gateway returns neutral JSON 503 BH_RESOURCE_UNAVAILABLE: the URL does not wake the server or expose the owner's billing state. Common errors: Errors.
The Gateway checks the parent token on every resource read. A network failure, timeout or malformed authority response returns neutral 503 BH_RESOURCE_UNAVAILABLE; confirmed revocation returns 401 BH_RESOURCE_URL_INVALID. The request is refused without falling back to a browser session or public access.
Known specifics
Main-page widget with PORTAL access
- Create one parent
api-bearertoken with the required lifetime and audience approval. - Sign the stylesheet and each image/font path separately through this operation.
- Use the signed stylesheet URL as
WIDGET_PARAMS.stylewhen registering throughlanding.repowidget.register. Use the corresponding signed URLs in CSSurl(...), HTML images and previews. - Renew the URLs and update widget registration before
expiresAt. Relative image paths do not inherit the stylesheet URL's signature and remain private. - Revoke the parent to stop every derived URL early.
Ordinary application URLs remain protected under PORTAL. The Gateway does not rewrite HTML/CSS or automatically sign dependencies. Resource requests do not create cookies or forward user identity or X-Vibe-Authorization; the application must serve the resource without a personal session. Responses carry Cache-Control: no-store and Referrer-Policy: no-referrer.