Skip to content
Markdown

Reference

Jog's advice API

Jog measures what every job uses on its machine: its CPU, its memory and its work disk. The advice API turns that into each job's right size. The Jog skill (https://usejog.com/skills/jog/SKILL.md) uses it; so can anything else. Every answer is JSON.

Tokens

Calls take a Jog personal access token: Authorization: Bearer jog_pat_…. A token acts for one person and reads advice only, of their accounts. It reads nothing else on Jog: no money, settings, logs or other pages. Advice is for an account's owners for now.

  • For an agent: POST https://usejog.com/api/device with {"name", "access": "advice", "org"} (org, an account's login, is optional: without it the token reads all the person's accounts). The person approves the code in their browser; a token for one account can be approved only by its owners. Poll POST /api/device/token with {"deviceCode"} every interval seconds until it answers key, handed over once. Until then it answers an error: authorization_pending (not approved yet), logins_busy_here (too many asks at once from that network: ask again after retryAfter seconds), busy (ask again in a few seconds), access_denied (declined) or expired_token (expired, or the key was already collected: ask for a new code). Asking for a code can also answer logins_busy or logins_busy_here, with retryAfter. Each approval makes a new token, which lasts 7 days; none replaces an older one, even of the same name, so revoke those no longer used.
  • For CI: the person makes one at https://usejog.com/account/-/tokens, for all their accounts or one, for 7, 30 or 90 days. It is shown once.

Revoke a token there, or with POST https://usejog.com/api/key/revoke and the token itself. Jog keeps only a token's hash. Its text is jog_pat_, 64 hex digits and 8 of check: the first 4 bytes of the SHA-256 of the rest.

GET/api/orgs/{org}/advice

version 3tokenJSON

Headers

NameType
AuthorizationBearer jog_pat_…
Jog-Route-Version3

Query

NameType
goaloptional"balanced" | "cost" | "speed"
untiloptionaltime

Every job's advice over the last 30 days. Send Jog-Route-Version: 3: this answer is at version 3, and a call naming an older version, or none, gets 409 updated. Query: goal (cost, balanced or speed; the account's own otherwise, balanced until it chooses) and until (the window's end, at most now, as 2026-10-24T23:36:10Z). Pass the first answer's window.end as until to every later read, of either route, so they all read the same window. A run Jog hears of late, or whose measure comes after its charge, can still join it: if two reads disagree about a job, read both again.

FieldWhat it is
goal"balanced" | "cost" | "speed"
nowtime
window (start, end).object
jobsobject[]one each, what is breaking first (failing, more-memory, go-back), then the changes to make, the most at stake first.
jobs[].kindstringtoday smaller, larger, more-memory, worked, go-back, failing (a move that fails and can't safely go back), few or right.
jobs[].reasonstring | nullwhy, as a code: for right, cpu, cost, memory, growth, killed, disk, smallest, largest ("The right size") or unknown, tried, drift, hardware ("No change advised": Jog isn't sure, or for hardware, can't estimate the job's time on Jog Max's 16 or 32 vCPUs, which can run on slower cores); for few, runs, unusable, none-passed, mixed, moved, max-runs (moved to Jog Max, whose runs alone count there), mixed-tier (on Jog and Jog Max lately) or failures (failing since it moved, not yet shown to be the size's fault); for a move, failing, killed, slower, cost, pace, room, unknown. Read both as text: a kind or reason added later comes with its own title and detail.
jobs[].title, detailthe advice in words, with its figures; each figure is a field below or worked out from the runs.
jobs[].jobobjectrepo (owner/name), repoId, workflow, workflowFile, name (GitHub's job name; a matrix leg's has its values).
jobs[].sizeInNamebooleanthe name holds a Jog size, as a leg named by its size does; changing its size renames it, and Jog can't follow the move.
jobs[].lastRunAttimewhen its newest run, on any size, was charged.
jobs[].sizestringthe runner the advice is about: of its runs on the tier its newest run used (Jog or Jog Max), since its last stretch on the other, the one most of the newest 10 used; or for a fresh move that fails, the one it moved to.
jobs[].tostring | nullthe runner to move to, or null. A job is advised from those runs alone, so size and to are both Jog's labels or both Jog Max's (jog-max, jog-max-4vcpu and so on); only memory, disk and kills count from both, since a size's machines have the same memory and disk on either. A job on both tiers lately (mixed-tier) gets no to.
jobs[].nowobjectits runs on size since it came from the size before (the window, without one): runs (the runs the advice counts), ran (every run), passed and failed (a run Jog ended at its job limit failed; any other cancelled run is neither), medianSeconds (the sample's median; 0 with no counted run), cost (micro-dollars spent, at the price each run was charged), costPerRun (a run that passed or failed, on average, at its tier's price now (Jog's, or Jog Max's); null with none), costPerPass (a passing run with its share of failed runs, on average, at its tier's price now, which a move compares; null with none passed), from (its first run).
jobs[].sampleobject | nullthe counted runs every time figure is of: runs, from, to.
jobs[].afterobject | nullthe other size judged and what it would make of the sample: size, medianSeconds (estimated; for a bigger size, at best), slowestTenth (for a smaller size, the most nine in ten of its runs would take there, in thousandths of their time now), cost, costMost. Set for smaller and larger, and on a right for the size it judged.
jobs[].beforeobject | nullthe size before (for a move, a failing size, or a size it tried), its runs as now has them, and since (when the runs on size began).
jobs[].memoryPeakBytes, memoryP95Bytes, diskPeakBytesof every run measured in the window on any size, each run's memory at most its own size's; null with none measured.
jobs[].memoryGrowthBytesinteger | nullhow much its memory grew a week lately on size, beside sizeMemoryPeakBytes, the most a run on size used.
jobs[].limitsobject | nullthe size the words hold the job against (size: to, after's size, or the size a kept or failing move can't go back to) and its memoryBytes and diskBytes. All in bytes.
jobs[].killedintegerruns of now killed for memory;
jobs[].killobject | nullthe one the words name (jobId, at, size);
jobs[].largestKillobject | nullfor more-memory with no to below Jog's largest size, the run killed there, which leaves no size to name.
jobs[].unmeasuredintegerpassing runs of now Jog couldn't use, so passed is runs plus unmeasured.
jobs[].unwholeintegerruns on size since the sample began that Jog didn't wholly measure.
Costs are over the last 30 days, or since now.from. Sizes and sentences write GB for GiB, 2^30 bytes.
Request
curl -G https://usejog.com/api/orgs/ACCOUNT/advice \
  -H "Authorization: Bearer $JOG_TOKEN" \
  -H "Jog-Route-Version: 3"
Response
{
  "goal": "balanced",
  "jobs": [
    {
      "after": {},
      "before": {},
      "detail": "Its CPU stayed under half of 8 vCPUs in most runs.",
      "diskPeakBytes": 2147483648,
      "job": {},
      "kill": {},
      "killed": 12,
      "kind": "smaller",
      "largestKill": {},
      "lastRunAt": "2026-10-24T23:36:10Z",
      "limits": {},
      "loadUsec": [],
      "memoryGrowthBytes": 2147483648,
      "memoryP95Bytes": 2147483648,
      "memoryPeakBytes": 2147483648,
      "now": {},
      "reason": "cpu",
      "sample": {},
      "size": "jog-8vcpu",
      "sizeInName": false,
      "sizeMemoryPeakBytes": 2147483648,
      "title": "Smaller and about as fast",
      "to": "jog-4vcpu",
      "unmeasured": 12,
      "unwhole": 12
    }
  ],
  "now": "2026-10-24T23:36:10Z",
  "window": {
    "end": "2026-10-24T23:36:10Z",
    "start": "2026-10-24T23:36:10Z"
  }
}

GET/api/orgs/{org}/advice/runs

version 2tokenJSON

Headers

NameType
AuthorizationBearer jog_pat_…
Jog-Route-Version2

Query

NameType
beforeAtoptionaltime
beforeJobIdoptionalinteger
joboptionalstring
repoIdoptionalinteger
untiloptionaltime
workflowFileoptionalstring

Every run in the window, on Jog or Jog Max, or one job's (repoId, workflowFile and job together), newest first, 1,000 a page. Send Jog-Route-Version: 2: this answer is at version 2, whose size can be Jog Max's, and a call naming an older version, or none, gets 409 updated. While next isn't null, ask again with beforeAt set to its at and beforeJobId to its jobId; the last page can be empty. Take the same until as the advice to read the same window. Each run: jobId, job, at, size, seconds, cost, counted (counted, not_passed, unmeasured), outcome (passed, failed, neither), cpuUsec, cpuPeakMillicpus, memoryPeakBytes, diskPeakBytes, ioReadBytes, ioWriteBytes, networkRxBytes, networkTxBytes, memoryKills. A job's passed and failed are counts of its runs' outcomes.

Request
curl -G https://usejog.com/api/orgs/ACCOUNT/advice/runs \
  -H "Authorization: Bearer $JOG_TOKEN" \
  -H "Jog-Route-Version: 2"
Response
{
  "next": {
    "at": "2026-10-24T23:36:10Z",
    "jobId": 31415926
  },
  "now": "2026-10-24T23:36:10Z",
  "runs": [
    {
      "at": "2026-10-24T23:36:10Z",
      "cost": 4180,
      "counted": "counted",
      "cpuPeakMillicpus": 12,
      "cpuUsec": 12,
      "diskPeakBytes": 2147483648,
      "ioReadBytes": 2147483648,
      "ioWriteBytes": 2147483648,
      "job": {},
      "jobId": 31415926,
      "loadUsec": [],
      "memoryKills": 12,
      "memoryPeakBytes": 2147483648,
      "networkRxBytes": 2147483648,
      "networkTxBytes": 2147483648,
      "outcome": "passed",
      "seconds": 12,
      "size": "jog-8vcpu"
    }
  ],
  "window": {
    "end": "2026-10-24T23:36:10Z",
    "start": "2026-10-24T23:36:10Z"
  }
}

Errors

{"error": code, "message": words}

StatusError
400bad_request
401bad_key (ended, revoked or malformed)
403key_not_allowed (a route a token can't call), not_owner
404not_found (an account the token doesn't reach is not found, as a stranger's is)
503busy (ask again in a few seconds)

The same runs always give the same advice under a goal.

  • Overview
  • Set up with a coding agent
  • Runners
  • Pricing
  • Job codes
  • Advice API