Skip to content
Hoody.com

Proxy hooks intercept container traffic before it reaches the real service backend. Each hook binds an HTTP match (method, path, and optional headers) to a script that runs inside the container proxy. Within a service, hooks are evaluated in declared order and the first match wins. All write operations are gated by an If-Match: file:v<N> ETag precondition that the API returns from any successful read; this prevents lost updates when concurrent writers operate on the same hook list.

Use these endpoints when you want to register, reorder, update, or remove MITM hook scripts for a specific service running inside a container.

Returns all hooks grouped by service for the given container, along with the current file_version and etag that subsequent writes must echo back.

NameInTypeRequiredDescription
idpathstringYesContainer ID
Terminal window
curl -X GET "https://api.hoody.com/api/v1/containers/{containerId}/proxy/hooks" \
-H "Authorization: Bearer <token>"
{
"statusCode": 200,
"message": "Proxy hooks listed successfully",
"data": {
"hooks": {
"auth": [
{
"id": "01h2x3y4z5a6b7c8d9e0f1g2h3",
"position": 0,
"match": {
"method": "POST",
"path": "/v1/login",
"headers": {
"content-type": "application/json"
}
},
"script": {
"subdomain": "audit",
"path": "/scripts/log-auth.js"
},
"timeout": 1000,
"applies_to": {
"groups": ["audit"]
}
}
]
},
"file_version": 42,
"etag": "file:v42"
}
}

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

Section titled “GET /api/v1/containers/{id}/proxy/hooks/{service}”

Returns the ordered hook array for a single service. Within a service the order is significant because evaluation is first-match-wins.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
Terminal window
curl -X GET "https://api.hoody.com/api/v1/containers/{containerId}/proxy/hooks/auth" \
-H "Authorization: Bearer <token>"
{
"statusCode": 200,
"message": "Service hooks listed successfully",
"data": {
"service": "auth",
"hooks": [
{
"id": "01h2x3y4z5a6b7c8d9e0f1g2h3",
"position": 0,
"match": {
"method": "POST",
"path": "/v1/login"
},
"script": {
"path": "/scripts/log-auth.js"
},
"timeout": 1000
},
{
"id": "01h2x3y4z5a6b7c8d9e0f1g2h4",
"position": 1,
"match": {
"method": "*",
"path": "/v1/logout"
},
"script": {
"path": "/scripts/log-logout.js"
},
"timeout": 500,
"applies_to": {
"groups": ["audit", "observability"]
}
}
],
"file_version": 42,
"etag": "file:v42"
}
}

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

Section titled “GET /api/v1/containers/{id}/proxy/hooks/{service}/{hookId}”

Fetches a single hook by id within a service.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
hookIdpathstringYes26-char Crockford base32 ULID (lowercase)
Terminal window
curl -X GET "https://api.hoody.com/api/v1/containers/{containerId}/proxy/hooks/auth/01h2x3y4z5a6b7c8d9e0f1g2h3" \
-H "Authorization: Bearer <token>"
{
"statusCode": 200,
"message": "Hook retrieved successfully",
"data": {
"hook": {
"id": "01h2x3y4z5a6b7c8d9e0f1g2h3",
"position": 0,
"match": {
"method": "POST",
"path": "/v1/login",
"headers": {
"content-type": "application/json"
}
},
"script": {
"subdomain": "audit",
"path": "/scripts/log-auth.js"
},
"timeout": 1000,
"applies_to": {
"groups": ["audit"]
}
},
"file_version": 42,
"etag": "file:v42"
}
}

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

Section titled “POST /api/v1/containers/{id}/proxy/hooks/{service}”

Appends a new hook to the end of the service array, or inserts it at a specific position. Omit position to append. Requires an If-Match: file:v<N> header so that conflicting concurrent writers do not silently overwrite each other.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
if-matchheaderstringNofile:v<N> ETag precondition
FieldTypeRequiredDescription
matchobjectYesHTTP match — method, path, and optional headers
scriptobjectYesScript reference — path is required
timeoutintegerNoHook execution budget in milliseconds (1-30000)
applies_toobjectNoRestrict hook to specific groups
positionintegerNo0-indexed insertion position (POST only)
Terminal window
curl -X POST "https://api.hoody.com/api/v1/containers/{containerId}/proxy/hooks/auth" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "If-Match: file:v42" \
-d '{
"match": {
"method": "POST",
"path": "/v1/login",
"headers": { "content-type": "application/json" }
},
"script": {
"subdomain": "audit",
"path": "/scripts/log-auth.js"
},
"timeout": 1000,
"applies_to": { "groups": ["audit"] }
}'
{
"statusCode": 201,
"message": "Hook created successfully",
"data": {
"hook": {
"id": "01h2x3y4z5a6b7c8d9e0f1g2h3",
"position": 0,
"match": {
"method": "POST",
"path": "/v1/login"
},
"script": {
"path": "/scripts/log-auth.js"
},
"timeout": 1000,
"applies_to": {
"groups": ["audit"]
}
},
"file_version": 43,
"etag": "file:v43"
}
}

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

Section titled “PUT /api/v1/containers/{id}/proxy/hooks/{service}/{hookId}”

Full-replaces a hook while preserving its id and position. Requires If-Match. The same path also accepts PATCH as a live alias, but the canonical verb is PUT.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
hookIdpathstringYes26-char Crockford base32 ULID (lowercase)
if-matchheaderstringNofile:v<N> ETag precondition
FieldTypeRequiredDescription
matchobjectYesHTTP match — method, path, and optional headers
scriptobjectYesScript reference — path is required
timeoutintegerNoHook execution budget in milliseconds (1-30000)
applies_toobjectNoRestrict hook to specific groups
positionintegerNo0-indexed insertion position (POST only)
Terminal window
curl -X PUT "https://api.hoody.com/api/v1/containers/{containerId}/proxy/hooks/auth/01h2x3y4z5a6b7c8d9e0f1g2h3" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "If-Match: file:v43" \
-d '{
"match": {
"method": "POST",
"path": "/v1/session/login",
"headers": { "content-type": "application/json" }
},
"script": {
"subdomain": "audit",
"path": "/scripts/log-session.js"
},
"timeout": 1500,
"applies_to": { "groups": ["audit", "observability"] }
}'
{
"statusCode": 200,
"message": "Hook replaced successfully",
"data": {
"hook": {
"id": "01h2x3y4z5a6b7c8d9e0f1g2h3",
"position": 0,
"match": {
"method": "POST",
"path": "/v1/session/login"
},
"script": {
"path": "/scripts/log-session.js"
},
"timeout": 1500,
"applies_to": {
"groups": ["audit", "observability"]
}
},
"file_version": 44,
"etag": "file:v44"
}
}

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

Section titled “PATCH /api/v1/containers/{id}/proxy/hooks/{service}/{hookId}/position”

Performs an atomic move of a hook within its service array. The body is { position: N }. 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 in the service array
Terminal window
curl -X PATCH "https://api.hoody.com/api/v1/containers/{containerId}/proxy/hooks/auth/01h2x3y4z5a6b7c8d9e0f1g2h3/position" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "If-Match: file:v44" \
-d '{ "position": 0 }'
{
"statusCode": 200,
"message": "Hook moved successfully",
"data": {
"hook": {
"id": "01h2x3y4z5a6b7c8d9e0f1g2h3",
"position": 0,
"match": {
"method": "POST",
"path": "/v1/session/login"
},
"script": {
"path": "/scripts/log-session.js"
},
"timeout": 1500
},
"file_version": 45,
"etag": "file:v45"
}
}

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

Section titled “DELETE /api/v1/containers/{id}/proxy/hooks/{service}”

Removes every hook under the named service. Returns the count of hooks removed and the new etag. Requires If-Match.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
if-matchheaderstringNofile:v<N> ETag precondition

This endpoint takes no request body.

Terminal window
curl -X DELETE "https://api.hoody.com/api/v1/containers/{containerId}/proxy/hooks/auth" \
-H "Authorization: Bearer <token>" \
-H "If-Match: file:v45"
{
"statusCode": 200,
"message": "Service hooks cleared successfully",
"data": {
"removed": 3,
"file_version": 46,
"etag": "file:v46"
}
}

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

Section titled “DELETE /api/v1/containers/{id}/proxy/hooks/{service}/{hookId}”

Removes a single hook. The service’s remaining hooks retain their existing positions. Requires If-Match.

NameInTypeRequiredDescription
idpathstringYesContainer ID
servicepathstringYesService name
hookIdpathstringYes26-char Crockford base32 ULID (lowercase)
if-matchheaderstringNofile:v<N> ETag precondition

This endpoint takes no request body.

Terminal window
curl -X DELETE "https://api.hoody.com/api/v1/containers/{containerId}/proxy/hooks/auth/01h2x3y4z5a6b7c8d9e0f1g2h3" \
-H "Authorization: Bearer <token>" \
-H "If-Match: file:v46"
{
"statusCode": 200,
"message": "Hook removed successfully",
"data": {
"file_version": 47,
"etag": "file:v47"
}
}