# How to Enable or Disable Specific API Endpoints Programmatically in Stirling-PDF

> Dynamically manage Stirling-PDF API endpoint access programmatically. Use the EndpointConfiguration bean to enable or disable endpoints at runtime for instant control.

- Repository: [Stirling Tools/Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF)
- Tags: how-to-guide
- Published: 2026-03-01

---

**Stirling-PDF provides the `EndpointConfiguration` bean to toggle REST endpoints at runtime; autowire this service and call `enableEndpoint()` or `disableEndpoint()` to control availability instantly, while the `EndpointInterceptor` automatically enforces these states with 403 Forbidden responses.**

Stirling-PDF exposes dozens of PDF manipulation capabilities through REST APIs, but not every deployment requires every feature. The application provides a robust mechanism to enable or disable specific API endpoints programmatically without restarting the server, managed through the `EndpointConfiguration` service in the Stirling-Tools/Stirling-PDF repository.

## Understanding the Endpoint Control Architecture

The endpoint governance system relies on two core components working together. The **`EndpointConfiguration`** bean maintains an internal map of enabled and disabled endpoints, while the **`EndpointInterceptor`** enforces these decisions at the request level.

### The EndpointConfiguration Service

Located in [`app/common/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/common/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java), this Spring service reads application YAML, environment variables, and runtime functional groups (such as "OpenCV" or "Python") during startup. It exposes public methods to manipulate endpoint states:

- **`enableEndpoint(String endpoint)`**: Forces the specified endpoint to be enabled, overriding any previous disable flag.
- **`disableEndpoint(String endpoint)`**: Disables the endpoint with a generic `CONFIG` reason.
- **`disableEndpoint(String endpoint, DisableReason reason)`**: Disables the endpoint with a specific reason (`CONFIG`, `DEPENDENCY`, or `UNKNOWN`) useful for logging and diagnostics.
- **`isEndpointEnabled(String endpoint)`**: Returns the current status of the endpoint, used by the interceptor and public controllers.

The **`DisableReason`** enum helps identify why an endpoint is unavailable, appearing in logs when the interceptor blocks requests.

### Request Interception and Enforcement

The `EndpointInterceptor` in [`app/core/src/main/java/stirling/software/SPDF/config/EndpointInterceptor.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/core/src/main/java/stirling/software/SPDF/config/EndpointInterceptor.java) intercepts every incoming HTTP request. It extracts the request path, queries `endpointConfiguration.isEndpointEnabled(path)`, and returns **403 Forbidden** with the message "Endpoint disabled" if the endpoint is inactive.

## Programmatically Toggling Endpoints

Because `EndpointConfiguration` is a standard Spring bean, any component can inject it to modify endpoint availability at runtime. This enables dynamic feature flags, dependency-based disabling, and automated testing scenarios.

### Enabling and Disabling Individual Endpoints

Inject the configuration bean into your service to toggle specific paths:

```java
@Service
public class RuntimeEndpointManager {

    private final EndpointConfiguration endpointConfig;

    public RuntimeEndpointManager(EndpointConfiguration endpointConfig) {
        this.endpointConfig = endpointConfig;
    }

    /** Disable the PDF conversion endpoint because an external library is missing */
    public void disablePdfConversion() {
        endpointConfig.disableEndpoint("/api/v1/convert/pdf",
                EndpointConfiguration.DisableReason.DEPENDENCY);
    }

    /** Re‑enable it after the dependency is restored */
    public void enablePdfConversion() {
        endpointConfig.enableEndpoint("/api/v1/convert/pdf");
    }

    /** Query current status */
    public boolean isPdfConversionActive() {
        return endpointConfig.isEndpointEnabled("/api/v1/convert/pdf");
    }
}

```

The methods directly manipulate the internal map that the interceptor checks on every request.

### Controlling Endpoint Groups

Endpoints belong to functional groups defined in `ExternalAppDepConfig` (e.g., all OpenCV-dependent operations). You can disable entire groups when dependencies are missing:

```java
@Service
public class GroupToggleService {

    private final EndpointConfiguration cfg;

    public GroupToggleService(EndpointConfiguration cfg) {
        this.cfg = cfg;
    }

    public void disableOpenCvGroup() {
        // All endpoints that belong to the "OpenCV" group are stored in endpointGroups map
        cfg.getEndpointGroups().getOrDefault("OpenCV", Set.of())
           .forEach(ep -> cfg.disableEndpoint(ep, EndpointConfiguration.DisableReason.DEPENDENCY));
    }

    public void enableOpenCvGroup() {
        cfg.getEndpointGroups().getOrDefault("OpenCV", Set.of())
           .forEach(cfg::enableEndpoint);
    }
}

```

The `getEndpointGroups()` method is exposed via Lombok `@Getter`, returning a map of group names to endpoint sets.

### Querying Status via REST

If you prefer HTTP-based inspection over direct bean injection, the `ConfigController` exposes a public endpoint:

```bash
GET /api/v1/config/endpoint-enabled?endpoint=/api/v1/convert/pdf

```

This delegates to `endpointConfiguration.isEndpointEnabled(...)` and returns a JSON boolean indicating availability.

### Automated Testing with Disabled Endpoints

Use the configuration bean in tests to verify behavior when features are unavailable:

```java
@SpringBootTest
@AutoConfigureMockMvc
class ConvertPdfEndpointTest {

    @Autowired MockMvc mvc;
    @Autowired EndpointConfiguration endpointConfig;

    @BeforeEach void blockEndpoint() {
        endpointConfig.disableEndpoint("/api/v1/convert/pdf");
    }

    @Test void conversionShouldBeForbiddenWhenDisabled() throws Exception {
        mvc.perform(post("/api/v1/convert/pdf")
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .param("file", "dummy"))
           .andExpect(status().isForbidden());
    }
}

```

This demonstrates runtime control by disabling the endpoint before asserting that the interceptor returns 403 Forbidden.

## Key Implementation Files

- **[`app/common/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/common/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java)**: Central service storing endpoint states, groups, and toggle methods.
- **[`app/core/src/main/java/stirling/software/SPDF/config/EndpointInterceptor.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/core/src/main/java/stirling/software/SPDF/config/EndpointInterceptor.java)**: MVC interceptor enforcing endpoint availability with 403 responses.
- **[`app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java)**: Public REST API for querying endpoint status.
- **[`app/core/src/main/java/stirling/software/SPDF/config/ExternalAppDepConfig.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/core/src/main/java/stirling/software/SPDF/config/ExternalAppDepConfig.java)**: Defines functional groups and auto-disables endpoints when external dependencies are missing.
- **[`app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java)**: YAML-mapped configuration feeding into the endpoint configuration logic.

## Summary

- **Autowire `EndpointConfiguration`** to programmatically enable or disable any REST endpoint at runtime without restarting Stirling-PDF.
- **Use `disableEndpoint(path, reason)`** to provide context for logs when blocking access due to missing dependencies or configuration.
- **Leverage endpoint groups** to toggle related functionality collectively by iterating over group mappings.
- **Rely on `EndpointInterceptor`** to automatically enforce states, returning 403 Forbidden for disabled endpoints.
- **Query status** either through the bean's `isEndpointEnabled()` method or the public `/api/v1/config/endpoint-enabled` REST endpoint.

## Frequently Asked Questions

### How does Stirling-PDF determine if an endpoint should be disabled at startup?

During initialization, the `EndpointConfiguration` bean executes `init()` and `processEnvironmentConfigs()` to load settings from `ApplicationProperties` and detect missing external dependencies via `ExternalAppDepConfig`. It populates `endpointStatuses` with explicit flags and `disabledGroups` for functional categories, checking these maps in `isEndpointEnabled()` when requests arrive.

### Can I disable an endpoint temporarily and re-enable it without restarting the server?

Yes. The `EndpointConfiguration` bean is a singleton Spring service that maintains state in memory. Calling `disableEndpoint()` immediately updates the internal map, and subsequent requests receive 403 Forbidden responses. Calling `enableEndpoint()` restores access instantly for all new requests.

### What happens when I try to call a disabled endpoint?

The `EndpointInterceptor` intercepts the request before it reaches the controller, checks `endpointConfiguration.isEndpointEnabled(path)`, and if false, aborts the request with HTTP status **403 Forbidden** and the body "Endpoint disabled". The reason (CONFIG, DEPENDENCY, or UNKNOWN) is logged server-side for diagnostics.

### Is there a way to disable entire categories of endpoints based on missing system dependencies?

Yes. The codebase uses functional groups like "OpenCV" and "Python" defined in `ExternalAppDepConfig`. When the system detects missing binaries, it can call `disableGroup()` (or manually iterate `getEndpointGroups().get("GroupName")`) to disable all related endpoints simultaneously, ensuring users receive consistent 403 responses for unavailable functionality.