Bragi Docs Help

Bragi API

Bragi exposes a small HTTP API so another system can trigger a Job, ask when one last finished, and register Job Callbacks to be told when a run ends.

Where it runs

The same endpoints are served by both the Bragi web application and the Scheduler Web API host, so point at whichever of the two is reachable from the calling system. The Scheduler API URL setting (Admin > Settings) records the Scheduler Web API address for an Environment.

Authentication

Every endpoint except GET /System/health requires a JWT bearer token.

API keys

A key is a row in bragi.scheduler_web_api_key: a ClientId, a ClientSecret, an Issuer, an Audience and a Type. For this API the Type, Issuer and Audience are all Bragi.

The same table also holds keys for the separate Bragi External API, which serves client data rather than Job control. Those carry External in all three fields and are not interchangeable with these: a token issued for one will not be accepted by the other.

Building a token

Bragi does not hand out tokens. POST /System/Login exists only in development builds, for Swagger's convenience, and is compiled out of a release build. The calling system signs its own token using the client secret it was given.

Part

Value

Algorithm

HS256

Signing key

The client secret, as UTF-8 bytes

iss

The key's Issuer, which is Bragi

aud

The key's Audience, which is Bragi

sub

Who or what the call is on behalf of. Bragi does not enforce this, so use it to attribute the call in your own logs

jti

A fresh GUID for each token

ClientId

The key's ClientId. Bragi does not use this to validate the token, but it identifies the calling system

Lifetime

Keep it short. Bragi's own tokens last 30 minutes

In C#:

var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, userId ?? clientId), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new Claim("ClientId", clientId) }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(clientSecret)); var token = new JwtSecurityToken( issuer: "Bragi", audience: "Bragi", claims: claims, expires: DateTime.UtcNow.AddMinutes(30), signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)); var bearer = new JwtSecurityTokenHandler().WriteToken(token);

Send it on every request as Authorization: Bearer <token>.

Bragi validates the issuer, the audience, the expiry and the signature. It accepts a signature made with any configured API key secret rather than looking one up by ClientId, so every key issued for this API can reach every endpoint. There is no per-key restriction on what a token may do.

Calling convention

Two things are easy to get wrong:

  • Parameters go in the query string, including on the POSTs. None of these endpoints read a JSON request body. POST /Jobs/RunJobNow?environmentName=Production&jobName=Daily%20Load is a complete request; a body would be ignored.

  • A refused call still answers 200 OK. Errors are reported in the response, not by the HTTP status. Check success, do not rely on the status code.

Responses

Every endpoint returns the same envelope:

{ "success": true, "message": "" }

Endpoints that return data add a result:

{ "result": "2026-08-04T02:04:31Z", "success": true, "message": "" }

When success is false, message says why: the Environment or Job was not found, the Job is not configured for API triggering, the Job is already running and no callbackUrl was given, or an unexpected error occurred.

Allow API Trigger

A Job carries an Allow API Trigger flag, set on the Job configuration screen. It gates the endpoints that cause work or change configuration. The read-only ones do not check it.

Endpoint

Needs Allow API Trigger

POST /Jobs/RunJobNow

Yes

POST /Jobs/ScheduleJob

Yes

POST /Jobs/RegisterCallback

Yes

POST /Jobs/UnregisterCallback

Yes, unless removing by callbackId, which names no Job

POST /Jobs/LastCompletedJob

No

GET /Jobs/Callbacks

No

Endpoints

System

Endpoint

Description

GET /System/health

Liveness check. The only endpoint that needs no token, so it is the one to point a monitor at.

GET /System/healthProtected

The same answer, but requires a valid token. Useful for checking your key and token signing work before debugging anything else.

Jobs

Endpoint

Parameters

Description

POST /Jobs/RunJobNow

environmentName, jobName, and optionally callbackUrl, callbackTriggerOn, callbackReference, runMode, runKey

Queues the Job to run immediately. See Job Callbacks for the callback parameters and Job Run Modes for the run mode ones.

POST /Jobs/ScheduleJob

environmentName, jobName, when

Sets the Job's next scheduled run to when. Send it as an ISO 8601 timestamp; it is converted to UTC.

POST /Jobs/LastCompletedJob

environmentName, jobName

Returns the Job's last successful completion time, or null if it has never completed.

POST /Jobs/RegisterCallback

environmentName, jobName, callbackUrl, and optionally triggerOn, name, callerReference

Registers a persistent Job Callback. Returns the new callback id.

POST /Jobs/UnregisterCallback

callbackId, or all of environmentName, jobName and callbackUrl

Removes a persistent callback.

GET /Jobs/Callbacks

environmentName, optionally jobName

Lists the persistent callbacks for an Environment. One shot callbacks are not listed.

Knowing when a Job has finished

RunJobNow returns as soon as the run is queued, not when it finishes. Two ways to find out the outcome:

  • Callbacks. Give RunJobNow a callbackUrl and Bragi posts the run outcome to it. This is the recommended approach, and Waiting for a Job: a worked example walks through a full implementation.

  • Polling LastCompletedJob. Record the time before triggering, then poll until the returned completion time moves past it. Slower and chattier, but it needs nothing of the calling system beyond the ability to make outbound calls, so it suits a system Bragi cannot reach back into.

02 October 2026