Your product POSTs staff time entries to RuleVerdict and gets reconciled regular and overtime hours back

1. Get an API key

Create one from your dashboard's Settings → API keys page. The key is shown exactly once, at creation — copy it somewhere safe.

2. Author and publish your overtime rules

Before you can evaluate anything, your organization needs at least one published ruleset — open your organization → Open rule editor in the dashboard and build one there. Every rule you publish gets a key (e.g. warehouse-ca) — that key is the ot_context you'll reference in step 3 below. A call naming an ot_context with no matching published ruleset fails with a 422.

Starting from scratch? Paste your contract or CBA text into the rule editor's "Draft with AI" panel and it drafts the accumulators and rules for you — still a draft until you review and publish it yourself.

3. Call the evaluate endpoint

Send the API key as a bearer token, and a list of staff time entries. You never send which organization the request is for — that's resolved from the key itself.

curl https://api.ruleverdict.example/v1/evaluate/ \
  -H "Authorization: Bearer rsk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "staff": [
      {
        "staff_ref": "emp-123",
        "entries": [
          {
            "ot_context": "warehouse-ca",
            "date": "2026-09-01",
            "start_time": "08:00",
            "stop_time": "17:00"
          }
        ]
      }
    ]
  }'
import requests

response = requests.post(
    "https://api.ruleverdict.example/v1/evaluate/",
    headers={"Authorization": "Bearer rsk_live_..."},
    json={
        "staff": [
            {
                "staff_ref": "emp-123",
                "entries": [
                    {
                        "ot_context": "warehouse-ca",
                        "date": "2026-09-01",
                        "start_time": "08:00",
                        "stop_time": "17:00",
                    }
                ],
            }
        ]
    },
)
print(response.json())
const response = await fetch("https://api.ruleverdict.example/v1/evaluate/", {
  method: "POST",
  headers: {
    Authorization: "Bearer rsk_live_...",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    staff: [
      {
        staff_ref: "emp-123",
        entries: [
          {
            ot_context: "warehouse-ca",
            date: "2026-09-01",
            start_time: "08:00",
            stop_time: "17:00",
          },
        ],
      },
    ],
  }),
});

const data = await response.json();
console.log(data);

A typical response:

{
  "results": [
    {
      "staff_ref": "emp-123",
      "entries": [
        {
          "ot_context": "warehouse-ca",
          "date": "2026-09-01",
          "outcomes": [
            {"rule_key": "daily_ot_over_8", "outcome_type": "...", "payload": {}}
          ],
          "reconciled": {}
        }
      ]
    }
  ]
}

4. Large batches, or ask to be queued

A large enough request is queued instead of answered immediately — you'll get back {"task_id": "...", "status": "queued"} with a 202 status. Poll GET /v1/evaluate-jobs/{task_id}/ with the same API key until status is "complete" or "failed".

Add "queued": true to the request body to force this path for a smaller batch too — the only way to get a webhook (below) instead of an immediate response.

5. Webhooks, instead of polling

Add a "callback_url" to the request and, once a queued job finishes (or fails), RuleVerdict's calculation engine POSTs it the exact same body a poll would return — no need to keep asking:

{
  "staff": [ ... ],
  "queued": true,
  "callback_url": "https://your-app.example/webhooks/ruleverdict"
}

Delivered to your endpoint:

{
  "task_id": "...",
  "status": "complete",
  "results": [ ... ]
}

Delivery is best-effort — a few retries, then it gives up — so a missed webhook is never a lost result: GET /v1/evaluate-jobs/{task_id}/ still has it. Only plain http(s) URLs are accepted, and the target can't be a loopback or private-network address.

6. Rate limits

Each API key is limited to a number of requests per minute set by your organization's plan (see pricing). A request over the limit gets back a 429 status.

Full reference

Every field, status code, and error shape is documented in the generated API reference:

Swagger UI ReDoc