Skip to content

Entorno en desarrollo activo: puedes notar cambios o funciones incompletas.

JAOT

Triggers

Triggers let you fire optimization solves via HTTP requests, authenticated with per-trigger secrets. Each trigger is pinned to a specific model version for reproducible results. Use triggers to integrate JAOT solves into your existing automation pipelines -- CI/CD systems, scheduled jobs, or event-driven architectures.

Overview

A trigger wraps a builder document + version pair behind an HTTP endpoint. When fired, it queues an async solve using the pinned version's model definition, optionally with override data for variable inputs.

Key concepts:

  • Per-trigger secret authentication -- each trigger has its own secret, independent of your API key
  • Version pinning -- triggers always solve against a specific model version for reproducibility
  • Override schema -- define which input fields can be overridden at fire time
  • Webhook delivery -- results are POSTed to your webhook URL when the solve completes

Create a trigger

POST /api/v2/triggers

Creates an HTTP event trigger pinned to a specific model version. The plaintext trigger_secret is returned only once in this response -- store it securely.

Authentication: API key (organization scope)

Request body

FieldTypeRequiredDescription
namestringYesHuman-readable trigger name
descriptionstringNoOptional description
document_idstringYesBuilder document to solve
version_idstringYesPinned model version
override_schemaarrayNoFields that can be overridden at fire time
solver_namestringNoSolver every run uses (auto, scip, highs, cbc, glpk, jaos). Leave it out to use the solver the pinned version names. An unknown name is refused with 422
webhook_urlstringNoURL to receive solve results
webhook_secretstringNoSecret for webhook signature verification
workspace_idstringNoWorkspace scope
import requests

response = requests.post(
    "https://jaot.io/api/v2/triggers",
    headers={"Authorization": "Bearer ok_live_..."},
    json={
        "name": "Daily warehouse restock",
        "description": "Runs every morning to optimize warehouse restocking",
        "document_id": "doc_abc123",
        "version_id": "ver_def456",
        "override_schema": [
            {"name": "demand_forecast", "type": "array", "required": True}
        ],
        "webhook_url": "https://your-app.com/webhooks/jaot",
        "webhook_secret": "whsec_your_signing_secret"
    }
)

trigger = response.json()
# Save the trigger_secret -- it will not be shown again
print(f"Trigger ID: {trigger['id']}")
print(f"Secret: {trigger['trigger_secret']}")

Response (201 Created)

{
  "id": "trg_a1b2c3d4",
  "organization_id": "org_b7e4d1a0",
  "created_by": "usr_3a9f21c4",
  "name": "Daily warehouse restock",
  "description": "Runs every morning to optimize warehouse restocking",
  "document_id": "doc_abc123",
  "version_id": "ver_def456",
  "trigger_secret": "a3f8b2c1d4e5f67890abcdef12345678...",
  "trigger_secret_prefix": "a3f8b2c1",
  "override_schema": [
    {"name": "demand_forecast", "type": "array", "required": true}
  ],
  "webhook_url": "https://your-app.com/webhooks/jaot",
  "is_enabled": true,
  "total_runs": 0,
  "created_at": "2026-02-19T08:00:00Z"
}

Tip: Pin a specific model version to ensure trigger results are reproducible. If the pinned version is unnamed, it is automatically promoted to a named version to protect it from the retention pruning policy. See the Versions page for version management details.


List triggers

GET /api/v2/triggers

Returns all triggers for your organization, newest first.

Authentication: API key (organization scope)

Query parameters

ParameterTypeDescription
document_idstringFilter by builder document
response = requests.get(
    "https://jaot.io/api/v2/triggers",
    headers={"Authorization": "Bearer ok_live_..."},
    params={"document_id": "doc_abc123"}
)

triggers = response.json()
for t in triggers:
    print(f"{t['name']} (enabled={t['is_enabled']}, runs={t['total_runs']})")

Response (200)

[
  {
    "id": "trg_a1b2c3d4",
    "name": "Daily warehouse restock",
    "document_id": "doc_abc123",
    "version_id": "ver_def456",
    "trigger_secret_prefix": "a3f8b2c1",
    "is_enabled": true,
    "total_runs": 47,
    "last_fired_at": "2026-02-19T06:00:00Z",
    "created_at": "2026-01-15T08:00:00Z"
  }
]

Get a trigger

GET /api/v2/triggers/{trigger_id}

Returns a single trigger by ID.

Authentication: API key (organization scope)

response = requests.get(
    "https://jaot.io/api/v2/triggers/trg_a1b2c3d4",
    headers={"Authorization": "Bearer ok_live_..."},
)
trigger = response.json()
print(f"{trigger['name']} (runs={trigger['total_runs']})")

Update a trigger

PATCH /api/v2/triggers/{trigger_id}

Partially update a trigger. The version_id is immutable after creation -- create a new trigger if you need to pin a different version.

Authentication: API key (organization scope)

Request body (all fields optional)

FieldTypeDescription
namestringUpdated trigger name
descriptionstringUpdated description
override_schemaarrayUpdated override fields
solver_namestring or nullSolver every run uses. null goes back to the solver the pinned version names
webhook_urlstringUpdated webhook URL
webhook_secretstringUpdated webhook secret
response = requests.patch(
    "https://jaot.io/api/v2/triggers/trg_a1b2c3d4",
    headers={"Authorization": "Bearer ok_live_...", "Content-Type": "application/json"},
    json={"name": "Warehouse restock v2", "webhook_url": "https://new-url.com/webhook"},
)

Delete a trigger

DELETE /api/v2/triggers/{trigger_id}

Permanently deletes a trigger and all its run history.

Authentication: API key (organization scope)

response = requests.delete(
    "https://jaot.io/api/v2/triggers/trg_a1b2c3d4",
    headers={"Authorization": "Bearer ok_live_..."},
)
# Response: 204 No Content

Toggle a trigger

POST /api/v2/triggers/{trigger_id}/toggle

Enable or disable a trigger without deleting it. Disabled triggers return 409 Conflict when fired.

Request body

FieldTypeRequiredDescription
enabledbooleanYesNew enabled state
response = requests.post(
    "https://jaot.io/api/v2/triggers/trg_a1b2c3d4/toggle",
    headers={"Authorization": "Bearer ok_live_...", "Content-Type": "application/json"},
    json={"enabled": False},
)
print(response.json())

Fire a trigger

POST /api/v2/triggers/{trigger_id}/fire

Fire a trigger to queue an async solve. Authentication uses the per-trigger secret (not your API key). Provide the secret via the Authorization: Bearer header or the trigger_secret field in the request body.

Authentication: Per-trigger secret

Request body

FieldTypeRequiredDescription
trigger_secretstringNoAlternative to Authorization header
override_dataobjectNoOverride values for fields defined in override_schema

A field you leave out of override_data takes its default from the schema, when it has one. A required field with a default does not have to be sent.

The run solves the pinned version, then applies the trigger's solver_name, then the overrides. So a solver named by an override, sent or taken from its default, wins over the trigger's solver.

import requests

# Fire with override data (e.g., today's demand forecast)
response = requests.post(
    "https://jaot.io/api/v2/triggers/trg_a1b2c3d4/fire",
    headers={"Authorization": "Bearer a3f8b2c1d4e5f6..."},
    json={
        "override_data": {
            "demand_forecast": [120, 85, 200, 150, 90]
        }
    }
)

result = response.json()
print(f"Run ID: {result['run_id']}, Status: {result['status']}")

Response (202 Accepted)

{
  "run_id": "run_x1y2z3w4",
  "status": "queued"
}

Errors

StatusDescription
401Missing or invalid trigger secret
404Trigger not found
409Trigger is disabled
422Override validation failed, or the model names a solver this server does not have

A 422 still records a run with status validation_failed, so the refused call shows in the run history. The body keeps detail as {"error", "run_id"} and adds a code beside it: trigger.override_unknown_fields, trigger.override_missing_required or trigger.solver_unavailable, with the values in params.


Run a trigger now

POST /api/v2/triggers/{trigger_id}/run

Queue one run with the trigger's own settings and override defaults. This is the Run now button on the trigger page. It authenticates with your session or API key, never with the trigger secret, and needs the solver role in the trigger's workspace. It counts against the same per-trigger limit as /fire.

A refused input answers 422 with the same code as /fire, and records no run.

Authentication: API key (organization scope)

Response (202 Accepted)

{
  "run_id": "trun_x1y2z3w4",
  "status": "pending"
}

List trigger runs

GET /api/v2/triggers/{trigger_id}/runs

Returns paginated run history for a trigger, newest first.

Authentication: API key (organization scope)

Query parameters

ParameterTypeDefaultDescription
pageint1Page number
page_sizeint20Items per page (max 100)
response = requests.get(
    "https://jaot.io/api/v2/triggers/trg_a1b2c3d4/runs",
    headers={"Authorization": "Bearer ok_live_..."},
    params={"page": 1, "page_size": 10},
)
runs = response.json()
for run in runs["items"]:
    print(f"{run['id']}: {run['status']}")

Response (200)

{
  "items": [
    {
      "id": "run_x1y2z3w4",
      "trigger_id": "trg_a1b2c3d4",
      "status": "completed",
      "override_data": {"demand_forecast": [120, 85, 200]},
      "result_data": {"objective_value": 4250.0, "status": "optimal"},
      "created_at": "2026-02-19T06:00:00Z",
      "completed_at": "2026-02-19T06:00:15Z"
    }
  ],
  "total": 47,
  "page": 1,
  "page_size": 10
}

Get a single run

GET /api/v2/triggers/{trigger_id}/runs/{run_id}

Returns full details for a run including result data and override data.

Authentication: API key (organization scope)


Rerun a previous run

POST /api/v2/triggers/{trigger_id}/runs/{run_id}/rerun

Queue a new run using the override data from a previous run. Authenticated via API key (not trigger secret), since the user is already authenticated.

The input is checked first. If it would be refused again, for example the run was validation_failed and the schema has not changed, the rerun answers 422 with a code and records no new run.

Authentication: API key (organization scope)

response = requests.post(
    "https://jaot.io/api/v2/triggers/trg_a1b2c3d4/runs/run_x1y2z3w4/rerun",
    headers={"Authorization": "Bearer ok_live_..."},
)
result = response.json()
print(f"New run: {result['run_id']}")

Response (202 Accepted)

{
  "run_id": "run_new_abc123",
  "status": "queued"
}