openapi: 3.1.0 info: title: OpenZeppelin Relayer Health Plugins API description: OpenZeppelin Relayer API termsOfService: https://www.openzeppelin.com/tos contact: name: OpenZeppelin url: https://www.openzeppelin.com license: name: AGPL-3.0 license url: https://github.com/OpenZeppelin/openzeppelin-relayer/blob/main/LICENSE version: 1.5.0 tags: - name: Plugins description: Plugins are TypeScript functions that can be used to extend the OpenZeppelin Relayer API functionality. paths: /api/v1/plugins: get: tags: - Plugins summary: List plugins. operationId: listPlugins parameters: - name: page in: query description: Page number for pagination (starts at 1) required: false schema: type: integer minimum: 0 - name: per_page in: query description: 'Number of items per page (default: 10)' required: false schema: type: integer minimum: 0 responses: '200': description: Plugins listed successfully content: application/json: schema: $ref: '#/components/schemas/ApiResponse_PaginatedResult_PluginModel' '400': description: BadRequest content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Bad Request success: false '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Unauthorized success: false '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Plugin with ID plugin_id not found success: false '429': description: Too Many Requests content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Too Many Requests success: false '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Internal Server Error success: false security: - bearer_auth: [] /api/v1/plugins/{plugin_id}: get: tags: - Plugins summary: Get plugin by ID operationId: getPlugin parameters: - name: plugin_id in: path description: The unique identifier of the plugin required: true schema: type: string responses: '200': description: Plugin retrieved successfully content: application/json: schema: $ref: '#/components/schemas/ApiResponse_PluginModel' example: data: allow_get_invocation: false config: featureFlag: true emit_logs: false emit_traces: false forward_logs: false id: my-plugin path: plugins/my-plugin.ts raw_response: false timeout: 30 error: null success: true '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Unauthorized success: false '404': description: Plugin not found content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Plugin with id my-plugin not found success: false '429': description: Too Many Requests content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Too Many Requests success: false '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Internal Server Error success: false security: - bearer_auth: [] patch: tags: - Plugins summary: Update plugin configuration description: 'Updates mutable plugin fields such as timeout, emit_logs, emit_traces, raw_response, allow_get_invocation, config, and forward_logs. The plugin id and path cannot be changed after creation. All fields are optional - only the provided fields will be updated. To clear the `config` field, pass `"config": null`.' operationId: updatePlugin parameters: - name: plugin_id in: path description: The unique identifier of the plugin required: true schema: type: string requestBody: description: Plugin configuration update. All fields are optional. content: application/json: schema: $ref: '#/components/schemas/UpdatePluginRequest' example: config: apiKey: xyz123 featureFlag: true emit_logs: true forward_logs: true timeout: 60 required: true responses: '200': description: Plugin updated successfully content: application/json: schema: $ref: '#/components/schemas/ApiResponse_PluginModel' example: data: allow_get_invocation: false config: apiKey: xyz123 featureFlag: true emit_logs: true emit_traces: false forward_logs: true id: my-plugin path: plugins/my-plugin.ts raw_response: false timeout: 60 error: null success: true '400': description: Bad Request (invalid timeout or other validation error) content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Timeout must be greater than 0 success: false '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Unauthorized success: false '404': description: Plugin not found content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Plugin with id my-plugin not found success: false '429': description: Too Many Requests content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Too Many Requests success: false '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Internal Server Error success: false security: - bearer_auth: [] /api/v1/plugins/{plugin_id}/call: get: tags: - Plugins summary: Execute a plugin via GET (must be enabled per plugin) description: 'This endpoint is disabled by default. To enable it for a given plugin, set `allow_get_invocation: true` in the plugin configuration. When invoked via GET: - `params` is an empty object (`{}`) - query parameters are passed to the plugin handler via `context.query` - wildcard route routing is supported the same way as POST (see `doc_call_plugin`) - Use the `route` query parameter or append the route to the URL path' operationId: callPluginGet parameters: - name: plugin_id in: path description: The unique identifier of the plugin required: true schema: type: string - name: route in: query description: Optional route suffix for custom routing (e.g., '/verify'). Alternative to appending the route to the URL path. required: false schema: type: string responses: '200': description: Plugin call successful content: application/json: schema: $ref: '#/components/schemas/ApiResponse_Value' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Unauthorized success: false '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Plugin with ID plugin_id not found success: false '405': description: Method Not Allowed (GET invocation disabled for this plugin) content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: 'GET requests are not enabled for this plugin. Set ''allow_get_invocation: true'' in plugin configuration to enable.' success: false '429': description: Too Many Requests content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Too Many Requests success: false '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Internal Server Error success: false security: - bearer_auth: [] post: tags: - Plugins summary: Execute a plugin with optional wildcard route routing description: 'Logs and traces are only returned when the plugin is configured with `emit_logs` / `emit_traces`. Plugin-provided errors are normalized into a consistent payload (`code`, `details`) and a derived message so downstream clients receive a stable shape regardless of how the handler threw. The endpoint supports wildcard route routing, allowing plugins to implement custom routing logic: - `/api/v1/plugins/{plugin_id}/call` - Default endpoint (route = "") - `/api/v1/plugins/{plugin_id}/call?route=/verify` - Custom route via query parameter - `/api/v1/plugins/{plugin_id}/call/verify` - Custom route via URL path (route = "/verify") The route is passed to the plugin handler via the `context.route` field. You can specify a custom route either by appending it to the URL path or by using the `route` query parameter.' operationId: callPlugin parameters: - name: plugin_id in: path description: The unique identifier of the plugin required: true schema: type: string - name: route in: query description: Optional route suffix for custom routing (e.g., '/verify'). Alternative to appending the route to the URL path. required: false schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/PluginCallRequest' required: true responses: '200': description: Plugin call successful content: application/json: schema: $ref: '#/components/schemas/ApiResponse_Value' example: data: done! error: null metadata: logs: - level: info message: Plugin started... traces: - method: sendTransaction relayerId: sepolia-example requestId: 6c1f336f-3030-4f90-bd99-ada190a1235b success: true '400': description: BadRequest (plugin-provided) content: application/json: schema: $ref: '#/components/schemas/ApiResponse_PluginHandlerError' example: data: code: VALIDATION_FAILED details: field: email error: Validation failed metadata: logs: - level: error message: 'Validation failed for field: email' success: false '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Unauthorized success: false '404': description: Not Found content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Plugin with ID plugin_id not found success: false '429': description: Too Many Requests content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Too Many Requests success: false '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ApiResponse_String' example: data: null error: Internal Server Error success: false security: - bearer_auth: [] components: schemas: LogEntry: type: object required: - level - message properties: level: $ref: '#/components/schemas/LogLevel' message: type: string PluginMetadata: type: object properties: logs: type: - array - 'null' items: $ref: '#/components/schemas/LogEntry' traces: type: - array - 'null' items: {} UpdatePluginRequest: type: object description: 'Request model for updating an existing plugin. All fields are optional to allow partial updates. Note: `id` and `path` are not updateable after creation.' properties: allow_get_invocation: type: - boolean - 'null' description: Whether to allow GET requests to invoke plugin logic config: type: - object - 'null' description: 'User-defined configuration accessible to the plugin (must be a JSON object) Use `null` to clear the config' additionalProperties: {} propertyNames: type: string emit_logs: type: - boolean - 'null' description: Whether to include logs in the HTTP response emit_traces: type: - boolean - 'null' description: Whether to include traces in the HTTP response forward_logs: type: - boolean - 'null' description: Whether to forward plugin logs into the relayer's tracing output raw_response: type: - boolean - 'null' description: Whether to return raw plugin response without ApiResponse wrapper timeout: type: - integer - 'null' format: int64 description: Plugin timeout in seconds minimum: 0 additionalProperties: false ApiResponse_PluginModel: type: object required: - success properties: data: type: object required: - id - path - timeout properties: allow_get_invocation: type: boolean description: Whether to allow GET requests to invoke plugin logic config: type: - object - 'null' description: User-defined configuration accessible to the plugin (must be a JSON object) additionalProperties: {} propertyNames: type: string emit_logs: type: boolean description: Whether to include logs in the HTTP response emit_traces: type: boolean description: Whether to include traces in the HTTP response forward_logs: type: boolean description: Whether to forward plugin logs into the relayer's tracing output id: type: string description: Plugin ID path: type: string description: Plugin path raw_response: type: boolean description: Whether to return raw plugin response without ApiResponse wrapper timeout: type: integer format: int64 description: Plugin timeout minimum: 0 error: type: string metadata: $ref: '#/components/schemas/PluginMetadata' pagination: $ref: '#/components/schemas/PaginationMeta' success: type: boolean LogLevel: type: string enum: - log - info - error - warn - debug - result ApiResponse_PluginHandlerError: type: object required: - success properties: data: type: object properties: code: type: - string - 'null' details: {} error: type: string metadata: $ref: '#/components/schemas/PluginMetadata' pagination: $ref: '#/components/schemas/PaginationMeta' success: type: boolean ApiResponse_PaginatedResult_PluginModel: type: object required: - success properties: data: type: object required: - items - total - page - per_page properties: items: type: array items: type: object required: - id - path - timeout properties: allow_get_invocation: type: boolean description: Whether to allow GET requests to invoke plugin logic config: type: - object - 'null' description: User-defined configuration accessible to the plugin (must be a JSON object) additionalProperties: {} propertyNames: type: string emit_logs: type: boolean description: Whether to include logs in the HTTP response emit_traces: type: boolean description: Whether to include traces in the HTTP response forward_logs: type: boolean description: Whether to forward plugin logs into the relayer's tracing output id: type: string description: Plugin ID path: type: string description: Plugin path raw_response: type: boolean description: Whether to return raw plugin response without ApiResponse wrapper timeout: type: integer format: int64 description: Plugin timeout minimum: 0 page: type: integer format: int32 minimum: 0 per_page: type: integer format: int32 minimum: 0 total: type: integer format: int64 minimum: 0 error: type: string metadata: $ref: '#/components/schemas/PluginMetadata' pagination: $ref: '#/components/schemas/PaginationMeta' success: type: boolean PaginationMeta: type: object required: - current_page - per_page - total_items properties: current_page: type: integer format: int32 minimum: 0 per_page: type: integer format: int32 minimum: 0 total_items: type: integer format: int64 minimum: 0 PluginCallRequest: type: object properties: params: description: Plugin parameters. If not provided, the entire request body will be used as params. ApiResponse_String: type: object required: - success properties: data: type: string error: type: string metadata: $ref: '#/components/schemas/PluginMetadata' pagination: $ref: '#/components/schemas/PaginationMeta' success: type: boolean ApiResponse_Value: type: object required: - success properties: data: {} error: type: string metadata: $ref: '#/components/schemas/PluginMetadata' pagination: $ref: '#/components/schemas/PaginationMeta' success: type: boolean securitySchemes: bearer_auth: type: http scheme: bearer