---
title: "API Access Plugin for Orangescrum Self-Hosted"
description: "REST and GraphQL API for Orangescrum self-hosted. Scoped API keys, signed webhooks, rate limits, and an offline Swagger and GraphiQL developer portal."
canonical: https://www.orangescrum.com/self-hosted/plugins/api-access
---

# API Access Plugin for Orangescrum Self-Hosted

> For the complete documentation index, see [llms.txt](https://www.orangescrum.com/llms.txt).

1.  [Home](/)
2.  ›
3.  [Self-Hosted](/self-hosted)
4.  ›
5.  [Plugins](/self-hosted/plugins)
6.  ›
7.  API Access

# API Access

by [Orangescrum](/) · Productivity

Self-HostedVerifiedDeveloper

Open Orangescrum to your own systems. Issue API keys with fixed scopes, call a versioned REST API or a single GraphQL endpoint, and receive signed webhooks when work changes. Rate limits, CORS, IP rules, and request logging are set from an admin screen. A bundled Swagger UI and GraphiQL run offline, so your developers can read and try the API without leaving your network.

Installs

Available

Active deployments

Support

Vendor Supported

Priority response

Trust

Self-Hosted

Your infra, your data

$499/year

Per company • Add-on to any Self-Hosted plan

[Buy & See All Plans](/self-hosted/pricing#addons)[Talk to Sales](/contact-sales)

-   Versioned REST API plus a GraphQL endpoint
-   Scoped API keys, hashed and shown once
-   Signed outbound webhooks with retry and delivery log
-   Rate limits with standard response headers
-   Admin screens for keys, settings, and webhooks
-   Offline Swagger UI and GraphiQL developer portal
-   Key scopes intersected with the acting role
-   Six capability keys for role-based access

Pairs with [Self-Hosted Core ($1,500/yr) or Business ($2,250/yr)](/self-hosted/pricing)

[Overview](#overview)[Features](#features)[About](#about)[Install](#install)[FAQ](#faq)

## Screenshots

API key management with the scope matrix

Webhook subscriptions and the delivery log

Bundled Swagger UI running offline at /developer

## Key Features

### Versioned REST API

A stable /api/v1 surface over projects, epics, features, stories, tasks, work items, and time logs, with a consistent response envelope, pagination, and per-resource filters.

### GraphQL Endpoint

One POST endpoint returns exactly the fields you ask for. Batched loading keeps nested queries from turning into a storm of database calls.

### Scoped API Keys

Each key carries a resource and action scope set, so an integration that only needs to read projects can never write tasks. Scopes are chosen when the key is created.

### Secrets Hashed, Shown Once

Only a lookup prefix and a SHA-256 hash are stored. The raw secret is displayed once at creation and never again, so a database copy does not hand over working credentials.

### Scopes Are Immutable

There is no action anywhere that widens an existing key's scopes. That is enforced on the server, not hidden in the interface. To change access you revoke the key and issue a new one.

### Role-Intersected Access

Every call is checked twice: against the key's scopes and against the role the key acts as. A key can never do more than the role behind it, so an over-scoped key is still contained.

### Service Account Keys

Issue keys that belong to a system rather than a person, acting as a role you choose. Your integrations stop breaking when the employee who created the key leaves.

### Configurable Rate Limiting

Set read and write limits per window, with a per-key override when one integration genuinely needs more. Responses carry limit, remaining, and reset headers, and a breach returns 429 with Retry-After.

### Signed Outbound Webhooks

Subscribe an endpoint to the events you care about. Each delivery carries an HMAC-SHA256 signature over the timestamp and body, so the receiver can prove the payload came from you and was not replayed.

### Delivery Log and Redelivery

Every attempt is recorded with status, response code, and error. Failed deliveries retry with exponential backoff, and you can redeliver by hand or send a test ping from the admin screen.

### Protected Webhook Targets

Target URLs must be HTTPS and are validated before they are saved. Loopback, private, and link-local addresses are rejected, so a webhook cannot be pointed back at your internal network.

### Events From Every Origin

Events are raised from the core data layer, not from the API controllers. A change made by a person in the interface fires the same webhook as a change made through the API.

### Offline Developer Portal

An OpenAPI 3.1 document, a bundled Swagger UI with try-it-out, and a bundled GraphiQL playground, all served from your own install with no calls to any outside CDN.

### Admin Settings Panel

Master switches for REST and GraphQL, rate limits, key expiry and per-user key caps, CORS origins, IP allow and deny rules, pagination defaults, request logging with retention, and GraphQL depth, complexity, and introspection limits.

### Capability-Based Permissions

Six capability keys cover viewing, creating, and revoking keys, managing service accounts, managing settings, and managing webhooks. Owner and Admin get them by default, and other roles do not.

### Stable External IDs

The API exposes UUIDs rather than internal numeric primary keys. Your integrations bind to identifiers that are safe to log, share, and keep.

## About this plugin

### Why API Access for Orangescrum?

Sooner or later something outside Orangescrum needs to read or change what is inside it: a data warehouse, an internal portal, a provisioning script, a finance system. Doing that against the database directly is how installs get broken. This add-on gives those systems a proper front door, with authentication, scoping, rate limits, and documentation.

### Two heads, one set of rules

REST and GraphQL sit behind the same authentication, the same scope checks, and the same rate limiter. Both delegate to the same services the application itself uses, so behaviour does not drift between what the interface does and what the API does. Choose whichever style suits the integration rather than choosing a different security model.

### Keys that fail safe

A key's scopes are fixed when it is created. There is no action that widens them, and that is enforced on the server rather than hidden in the interface. Every request is then checked against both the key's scopes and the role the key acts as, so a key can never exceed the role behind it. Only a prefix and a hash are stored, so a database dump does not yield working credentials.

### Webhooks you can verify and replay

Subscribe an endpoint to the events you care about and each delivery arrives with an HMAC-SHA256 signature over the timestamp and body. Failures retry with exponential backoff and every attempt is logged with its response code, so a broken receiver becomes a thing you can see and redeliver rather than a silent gap. Events are raised from the core data layer, which means a change made by a person in the interface fires the same webhook as one made through the API.

### Documentation that works behind your firewall

The OpenAPI document, Swagger UI, and GraphiQL are all bundled with the plugin and served from your own install. There are no calls to an outside CDN, which matters when the whole reason you run self-hosted is that the environment has no route to the public internet. On the marketing site the same reference is published at /developer and /developer/api if you want to read it before you buy.

### Limits you set, not limits you discover

Read and write rate limits, key expiry, per-user key caps, CORS origins, IP allow and deny rules, pagination caps, request logging with retention, and GraphQL depth and complexity limits are all settings. One badly written integration cannot take the server down, and you find that out by configuring it rather than by an outage.

### What's included

-   REST API at /api/v1 with a consistent response envelope and pagination
-   Endpoints for projects, epics, features, stories, tasks, work items, and time logs
-   Test suite, test case, test run, test defect, and test resource endpoints when Test Case Management is installed
-   GraphQL endpoint sharing the same authentication, scoping, and rate limits
-   Batched GraphQL loading to avoid repeated database calls on nested queries
-   GraphQL query depth, complexity, and introspection controls
-   API key authentication by header or bearer token
-   Per-key resource and action scopes, fixed at creation
-   SHA-256 key hashing with a one-time secret reveal
-   Key expiry, revoke, and delete
-   Per-user keys and service account keys that act as a chosen role
-   Authorisation as the acting role intersected with the key scopes
-   Rate limiting per key with per-company defaults and per-key overrides
-   Rate limit response headers plus 429 with Retry-After
-   Outbound webhook subscriptions with per-subscription signing secrets
-   HMAC-SHA256 request signing on every webhook delivery
-   Asynchronous webhook delivery through the queue worker
-   Retry with exponential backoff, full delivery log, and manual redelivery
-   Webhook test ping from the admin screen
-   HTTPS-only webhook targets with loopback and private address rejection
-   Events raised from the core data layer, so interface changes fire webhooks too
-   Admin screens for keys, settings, webhooks, and deliveries
-   Settings for CORS, IP allow and deny rules, pagination caps, and request logging with retention
-   Six capability permissions across keys, service accounts, settings, and webhooks
-   OpenAPI 3.1 document with bundled Swagger UI and GraphiQL, served offline
-   UUID external identifiers rather than internal numeric primary keys
-   Multi-tenant company-scoped data isolation

### Compatibility

Requires the Orangescrum Self-Hosted edition running PHP 8.2+, CakePHP 4.6+, and PostgreSQL 16. The plugin folder is PublicApi and it is gated by the PUBLIC\_API\_ENABLED flag in config/constants.php. Test management endpoints register only when the Test Case Management plugin is loaded. Webhook delivery runs through the queue worker, so that worker must be running. Rate limit counters use the configured cache: the file cache is fine on a single node, and a shared cache such as Redis is needed if you run more than one application node.

## Installation

A self-hosted install takes a few minutes. Buy the add-on, drop the plugin into your `plugins/` directory, run the migrations, and you're live.

1.  1
    
    ### Buy the add-on
    
    Purchase the API Access add-on from /self-hosted/pricing at $499/year per company, payable annually.
    
2.  2
    
    ### Drop the plugin into your install
    
    Copy the PublicApi/ folder into plugins/ on your self-hosted Orangescrum server.
    
3.  3
    
    ### Enable the feature flag and register the plugin
    
    Add \`define('PUBLIC\_API\_ENABLED', true);\` to config/constants.php and register \`PublicApi\` in src/Application.php with \`routes => true, bootstrap => true\`. While the flag is false the plugin does not load at all.
    
4.  4
    
    ### Run the database migrations
    
    Run \`bin/cake migrations migrate -p PublicApi\` to create the API key, settings, permission, webhook, and delivery tables.
    
5.  5
    
    ### Seed permissions and the menu
    
    Run \`bin/cake migrations seed -p PublicApi --seed PublicApiRbacSeeder\` to register the module, menu, and role permissions. On an existing install also run \`bin/cake backfill\_role\_rbac\` so custom roles pick up the new permissions. Both are safe to run more than once.
    
6.  6
    
    ### Configure your API settings
    
    Set read and write rate limits, key expiry and per-user key caps, CORS origins, IP allow and deny rules, pagination caps, request logging and retention, and the GraphQL depth and complexity limits.
    
7.  7
    
    ### Generate your first key
    
    Choose the scopes and expiry, decide whether it belongs to a user or is a service account key, and copy the secret straight away. It is shown once and cannot be retrieved later.
    
8.  8
    
    ### Register a webhook and test it
    
    Add an HTTPS endpoint, choose the events it should receive, and send a test ping. Make sure the queue worker is running, since deliveries are dispatched through it rather than in the request.
    

## Frequently Asked Questions

### What can the API read and write?

▾

Projects and the work hierarchy: epics, features, stories, tasks, work items, and time logs. If the Test Case Management plugin is also installed, test suites, test cases, test runs, test defects, and test resources are available as well. Those extra endpoints register only when that plugin is loaded.

### How are API keys kept secure?

▾

Only a lookup prefix and a SHA-256 hash of the secret are stored, and the comparison is constant time. The raw secret is shown once when the key is created and never again. Keys can carry an expiry date, be revoked, or be deleted, and a revoked key stops working on the next request.

### Can I change a key's scopes later?

▾

No, and this is deliberate. Scopes are fixed when the key is created and there is no update path in the API or the admin screen. If an integration needs different access, delete the key and generate a new one. Separately, a key can never do more than the role it acts as, so widening scopes would not grant permissions the role does not already have.

### Does it support webhooks?

▾

Yes, outbound only. You subscribe an endpoint to event types and each delivery is signed with HMAC-SHA256 over the timestamp and body. Failures retry with exponential backoff, every attempt is logged, and you can redeliver manually or send a test ping. There is no inbound webhook receiver: this add-on sends events out, it does not accept them in.

### Is there a GraphQL API as well as REST?

▾

Yes. GraphQL is a single POST endpoint inside the same route scope, so it shares the same key authentication, scope checks, and rate limiting. Nested queries use batched loading to avoid repeated database calls, and you can cap query depth and complexity and switch introspection off.

### How do I stop one integration overloading the server?

▾

Set read and write rate limits per window from the settings screen, with a per-key override when one integration genuinely needs more. Responses carry limit, remaining, and reset headers, and a breach returns 429 with Retry-After. You can also restrict access with IP allow and deny rules and cap page sizes.

### Where is the API documentation?

▾

An OpenAPI 3.1 document, a Swagger UI with try-it-out, and a GraphiQL playground are bundled with the plugin and served from your own install with no external CDN calls. Our published reference is at /developer and /developer/api if you want to read it before buying.
