Skip to main content
Custom API endpoints let you add your own HTTP endpoints to the Orchestrator. Use custom APIs to build health checks, webhook receivers, token exchange endpoints, or any custom endpoint that needs access to sessions, caches, and other Orchestrator services. Custom APIs are managed through the Service Extensions area in the Console — they are not an application type.

Console UI Workflow

1

Open Service Extensions

Navigate to Service Extensions in the Console sidebar and select API.
2

Create the API

Click Create and provide a name for the API endpoint and a function name that matches the Go function in your extension code (e.g., ServeAPI).
3

Write the extension code

Use the built-in code editor to write your serveSE handler, or upload a .go source file. The editor provides syntax highlighting and access to the service extension SDK.
4

Attach to a deployment

Go to the deployment’s Settings page. In the APIs section, attach the API you created. This includes the API in the deployment’s configuration bundle.
5

Publish

Publish the deployment to push the updated configuration bundle to your Orchestrator instances.

Request Lifecycle

Unlike other hooks that run during request processing, serveSE runs once when the Orchestrator starts up. Your extension registers HTTP route handlers that then execute whenever a matching request arrives.

Hooks

serveSE

Register custom HTTP endpoints on the Orchestrator. This hook runs at startup and gives you access to the router to define your own API routes. Use this to implement custom REST endpoints, webhook receivers, or internal service APIs. Signature:
func ServeAPI(api orchestrator.Orchestrator) error
App types: Top-level apis[] Config location: apis[].serveSE Parameters:
ParameterTypeDescription
apiorchestrator.OrchestratorAccess to sessions, caches, secrets, logging, router, and other Orchestrator services
Returns: error — return nil on success, or an error if the API handler setup fails. Examples:
When you need to receive webhooks at the Orchestrator and relay them to an external system — such as a SIEM, logging platform, or notification service — this extension registers a /webhooks/forward endpoint that accepts incoming requests and forwards them using a reusable HTTP client.
webhook-forwarder.go
package main

import (
    "fmt"
    "io"
    "net/http"
    "time"

    "github.com/strata-io/service-extension/orchestrator"
)

func ServeAPI(api orchestrator.Orchestrator) error {
    logger := api.Logger()

    // Create a reusable HTTP client at startup. Reusing clients pools
    // TCP connections and prevents resource exhaustion under load.
    apiHTTP := api.HTTP()
    err := apiHTTP.SetClient("forwarder", &http.Client{
        Timeout: 10 * time.Second,
    })
    if err != nil {
        return fmt.Errorf("failed to create HTTP client: %w", err)
    }

    // Read the destination URL from SE metadata.
    metadata := api.Metadata()
    targetURL := metadata["targetURL"].(string)

    // Read the auth token from the secret provider.
    sp := api.SecretProvider()
    authToken, err := sp.GetString("webhook-auth-token")
    if err != nil {
        return fmt.Errorf("failed to get auth token: %w", err)
    }

    router := api.Router()
    router.HandleFunc("/webhooks/forward", func(rw http.ResponseWriter, req *http.Request) {
        client, _ := apiHTTP.GetClient("forwarder")

        fwd, err := http.NewRequest(req.Method, targetURL, req.Body)
        if err != nil {
            logger.Error("se", "failed to create forward request", "error", err.Error())
            http.Error(rw, "internal error", http.StatusInternalServerError)
            return
        }
        fwd.Header.Set("Content-Type", req.Header.Get("Content-Type"))
        fwd.Header.Set("Authorization", "Bearer "+authToken)

        resp, err := client.Do(fwd)
        if err != nil {
            logger.Error("se", "failed to forward webhook", "error", err.Error())
            http.Error(rw, "forwarding failed", http.StatusBadGateway)
            return
        }
        defer resp.Body.Close()

        rw.WriteHeader(resp.StatusCode)
        io.Copy(rw, resp.Body)
    })

    logger.Info("se", "registered /webhooks/forward endpoint")
    return nil
}

Configuration

Custom API endpoints are defined under the apis top-level key in the deployment configuration.
maverics.yaml
apis:
  - name: my-custom-endpoint
    serveSE:
      funcName: ServeAPI
      file: /path/to/api-handler.go

Field Reference

KeyTypeDefaultRequiredDescription
apis[].namestringYesUnique name for the API endpoint
apis[].serveSEServiceExtensionYesService extension that handles requests to this endpoint
The serveSE field accepts the standard ServiceExtension object (funcName, code/file, metadata, goPath, allowedProtectedPackages).

Validation Rules

  • Each name must be unique across all apis[] entries
  • The serveSE field is required — an API endpoint without a handler is invalid

Example

A custom health check endpoint and a user info endpoint:
maverics.yaml
apis:
  - name: custom-health
    serveSE:
      funcName: HealthCheck
      file: /etc/maverics/extensions/health-check.go
      metadata:
        backendURL: "https://backend.example.com/health"

  - name: user-info
    serveSE:
      funcName: GetUserInfo
      file: /etc/maverics/extensions/user-info.go
Multiple custom APIs can be defined, each with its own service extension handler.

Service Extensions Overview

Configuration, SDK reference, and best practices

Applications

Application configuration for proxy, OIDC, and SAML apps