Skip to content

Proxy Hooks let you attach MITM-style intercept scripts to specific paths on a container service. Hooks are evaluated per-service in position order, first-match-wins. All mutating operations are ETag-gated via the If-Match: file:v header to prevent lost updates.

GET /api/v1/containers/{id}/proxy/hooks

Returns every hook for the container grouped by service, alongside the current file_version and ETag.

NameInTypeRequiredDescription
idpathstringYesContainer ID
{
"statusCode": 200,
"message": "Proxy hooks listed successfully",
"data": {
"hooks": {
"auth": [
{
"id": "01hz8x9k2b3c4d5e6f7g8h9j0k",
"position": 0,
"match": {
"method": "POST",
"path": "/v1/login",
"headers": {
"x-tenant": "acme"
}
},
"script": {
"subdomain": "hooks",
"execId": "exec_01hz8x9k2b3c4d5e6f7g8h9j0k",
"path": "/hooks/login-trace.js"
},
"timeout": 5000,
"applies_to": {
"groups": ["admins", "sre"]
}
}
],
"billing": []
},
"file_version": 42,
"etag": "file:v42"
}
}
const { data } = await client.api.proxyHooks.listContainerProxyHooks({
id: "container_01hz8x9k2b3c4d5e6f7g8h9j0k",
});

GET /api/v1/containers/{id}/proxy/hooks/{service}

Returns the ordered hook array for a single service. Within the list, evaluation is first-match-wins by position order.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
{
"statusCode": 200,
"message": "Service hooks listed successfully",
"data": {
"service": "auth",
"hooks": [
{
"id": "01hz8x9k2b3c4d5e6f7g8h9j0k",
"position": 0,
"match": {
"method": ["POST", "PUT"],
"path": "/v1/login",
"headers": {
"x-tenant": "acme"
}
},
"script": {
"subdomain": "hooks",
"execId": "exec_01hz8x9k2b3c4d5e6f7g8h9j0k",
"path": "/hooks/login-trace.js"
},
"timeout": 5000,
"applies_to": {
"groups": ["admins", "sre"]
}
}
],
"file_version": 42,
"etag": "file:v42"
}
}
const { data } = await client.api.proxyHooks.listContainerProxyServiceHooks({
id: "container_01hz8x9k2b3c4d5e6f7g8h9j0k",
service: "auth",
});

GET /api/v1/containers/{id}/proxy/hooks/{service}/{hookId}

Returns the hook identified by hookId under the given service.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
hookIdpathstringYes26-char Crockford base32 ULID (lowercase)
{
"statusCode": 200,
"message": "Hook retrieved successfully",
"data": {
"hook": {
"id": "01hz8x9k2b3c4d5e6f7g8h9j0k",
"position": 0,
"match": {
"method": "*",
"path": "/v1/login",
"headers": {
"x-tenant": "acme"
}
},
"script": {
"subdomain": "hooks",
"execId": "exec_01hz8x9k2b3c4d5e6f7g8h9j0k",
"path": "/hooks/login-trace.js"
},
"timeout": 5000,
"applies_to": {
"groups": ["admins"]
}
},
"file_version": 42,
"etag": "file:v42"
}
}
const { data } = await client.api.proxyHooks.getContainerProxyHook({
id: "container_01hz8x9k2b3c4d5e6f7g8h9j0k",
service: "auth",
hookId: "01hz8x9k2b3c4d5e6f7g8h9j0k",
});

POST /api/v1/containers/{id}/proxy/hooks/{service}

Creates a new hook under the given service. Omit position to append; supply a 0-indexed position to insert. Requires If-Match: file:v.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
if-matchheaderstringNofile:v<N> ETag precondition
FieldTypeRequiredDescription
matchobjectYesRequest matcher. Contains method (string or array of strings from *, GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS), path (string, max 257 chars), and headers (object of string values).
scriptobjectYesScript reference. path is required; optionally subdomain and execId.
timeoutintegerNoExecution timeout in ms (1–30000).
applies_toobjectNoRestriction object. groups is an array of group name strings (min 1).
positionintegerNo0-indexed insertion position (POST only).
{
"match": {
"method": "POST",
"path": "/v1/login",
"headers": {
"x-tenant": "acme"
}
},
"script": {
"subdomain": "hooks",
"execId": "exec_01hz8x9k2b3c4d5e6f7g8h9j0k",
"path": "/hooks/login-trace.js"
},
"timeout": 5000,
"applies_to": {
"groups": ["admins"]
}
}
{
"statusCode": 201,
"message": "Hook created successfully",
"data": {
"hook": {
"id": "01hz8x9k2b3c4d5e6f7g8h9j0k",
"position": 0,
"match": {
"method": "POST",
"path": "/v1/login",
"headers": {
"x-tenant": "acme"
}
},
"script": {
"subdomain": "hooks",
"execId": "exec_01hz8x9k2b3c4d5e6f7g8h9j0k",
"path": "/hooks/login-trace.js"
},
"timeout": 5000,
"applies_to": {
"groups": ["admins"]
}
},
"file_version": 43,
"etag": "file:v43"
}
}
const { data } = await client.api.proxyHooks.addContainerProxyHook({
id: "container_01hz8x9k2b3c4d5e6f7g8h9j0k",
service: "auth",
"if-match": "file:v42",
data: {
match: { method: "POST", path: "/v1/login" },
script: { path: "/hooks/login-trace.js" },
timeout: 5000,
},
});

PATCH /api/v1/containers/{id}/proxy/hooks/{service}/{hookId}

Full-replaces the hook at the given id, preserving its id and position. Requires If-Match.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
hookIdpathstringYes26-char Crockford base32 ULID (lowercase)
if-matchheaderstringNofile:v<N> ETag precondition
FieldTypeRequiredDescription
matchobjectYesRequest matcher. Contains method (string or array of strings from *, GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS), path (string, max 257 chars), and headers (object of string values).
scriptobjectYesScript reference. path is required; optionally subdomain and execId.
timeoutintegerNoExecution timeout in ms (1–30000).
applies_toobjectNoRestriction object. groups is an array of group name strings (min 1).
positionintegerNo0-indexed insertion position (POST only).
{
"match": {
"method": "POST",
"path": "/v1/login",
"headers": {
"x-tenant": "acme"
}
},
"script": {
"subdomain": "hooks",
"execId": "exec_01hz8x9k2b3c4d5e6f7g8h9j0k",
"path": "/hooks/login-trace.js"
},
"timeout": 5000,
"applies_to": {
"groups": ["admins"]
}
}
{
"statusCode": 200,
"message": "Hook updated successfully",
"data": {
"hook": {
"id": "01hz8x9k2b3c4d5e6f7g8h9j0k",
"position": 0,
"match": {
"method": "POST",
"path": "/v1/login",
"headers": {
"x-tenant": "acme"
}
},
"script": {
"subdomain": "hooks",
"execId": "exec_01hz8x9k2b3c4d5e6f7g8h9j0k",
"path": "/hooks/login-trace.js"
},
"timeout": 5000,
"applies_to": {
"groups": ["admins"]
}
},
"file_version": 43,
"etag": "file:v43"
}
}
const { data } = await client.api.proxyHooks.updateContainerProxyHook({
id: "container_01hz8x9k2b3c4d5e6f7g8h9j0k",
service: "auth",
hookId: "01hz8x9k2b3c4d5e6f7g8h9j0k",
"if-match": "file:v42",
data: {
match: { method: "POST", path: "/v1/login" },
script: { path: "/hooks/login-trace.js" },
timeout: 5000,
},
});

PATCH /api/v1/containers/{id}/proxy/hooks/{service}/{hookId}/position

Atomically reorders a single hook. Body must contain the target position. Requires If-Match.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
hookIdpathstringYes26-char Crockford base32 ULID (lowercase)
if-matchheaderstringNofile:v<N> ETag precondition
FieldTypeRequiredDescription
positionintegerYes0-indexed target position.
{
"position": 2
}
{
"statusCode": 200,
"message": "Hook moved successfully",
"data": {
"hook": {
"id": "01hz8x9k2b3c4d5e6f7g8h9j0k",
"position": 2,
"match": {
"method": "POST",
"path": "/v1/login",
"headers": {
"x-tenant": "acme"
}
},
"script": {
"subdomain": "hooks",
"execId": "exec_01hz8x9k2b3c4d5e6f7g8h9j0k",
"path": "/hooks/login-trace.js"
},
"timeout": 5000,
"applies_to": {
"groups": ["admins", "sre"]
}
},
"file_version": 43,
"etag": "file:v43"
}
}
const { data } = await client.api.proxyHooks.moveContainerProxyHook({
id: "container_01hz8x9k2b3c4d5e6f7g8h9j0k",
service: "auth",
hookId: "01hz8x9k2b3c4d5e6f7g8h9j0k",
"if-match": "file:v42",
data: { position: 2 },
});

DELETE /api/v1/containers/{id}/proxy/hooks/{service}

Removes every hook under the given service. Requires If-Match.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
if-matchheaderstringNofile:v<N> ETag precondition
{
"statusCode": 200,
"message": "Service hooks cleared",
"data": {
"removed": 3,
"file_version": 44,
"etag": "file:v44"
}
}
const { data } = await client.api.proxyHooks.clearContainerProxyServiceHooks({
id: "container_01hz8x9k2b3c4d5e6f7g8h9j0k",
service: "auth",
"if-match": "file:v42",
});

DELETE /api/v1/containers/{id}/proxy/hooks/{service}/{hookId}

Deletes a single hook by id. Requires If-Match.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
hookIdpathstringYes26-char Crockford base32 ULID (lowercase)
if-matchheaderstringNofile:v<N> ETag precondition
{
"statusCode": 200,
"message": "Hook removed successfully",
"data": {
"file_version": 44,
"etag": "file:v44"
}
}
await client.api.proxyHooks.removeContainerProxyHook({
id: "container_01hz8x9k2b3c4d5e6f7g8h9j0k",
service: "auth",
hookId: "01hz8x9k2b3c4d5e6f7g8h9j0k",
"if-match": "file:v42",
});