curl on localhost can drive an entire application.
1. Create blocks until the fields arrive
POST /api/auto-apply/applications holds the connection while Jobo validates
the target, acquires a browser, opens the form, and extracts its fields —
typically 10 seconds to 3 minutes. The response is the application with
status: "awaiting_answers" and the fields to answer in current_step:
status: "failed" with a
failure code.
Keep your HTTP client timeout above 540 seconds: the server holds a
blocking call for up to ~9 minutes before answering 202 with a snapshot
(see Recovery for what to do then).
2. Answers are validated synchronously — mistakes are free
POST /api/auto-apply/applications/{id}/answers takes the complete answer
snapshot for the current step:
400 validation_failed immediately, with
per-field detail in errors:
correction_round in the request is an optional guard: when present
and stale, the API refuses with 409 stale_correction_round rather than
answering the wrong round.)
Once the answers are accepted, Jobo fills the page and advances the form —
intermediate pages auto-continue, the final page auto-submits; the
browser agent decides which from the page itself. The call then blocks until
one of three outcomes:
3. Correction rounds
Client-side validation cannot predict everything the employer’s ATS enforces. When the ATS rejects a value after filling, the same step comes back withcorrection_round incremented and command_errors describing what was
rejected:
correction_limit_exceeded.
4. Deadlines
While a step is awaiting answers, a real browser is holding the employer’s form open. Each answerable step carriesanswers_expire_at — about 3
minutes, capped at 60 seconds for one-time verification-code steps.
Past the deadline the application fails with answers_timeout
(verification_timeout for code steps). Answer promptly; if your answer
source is slow, compute answers before creating the application.
A verification code is an ordinary answer — read it from the candidate’s inbox
however you already do and submit it like any other. If you would rather not
build inbox access, connected mailboxes
are an optional convenience that resolves the code (or confirmation link) for
you; nothing here requires them.
5. Recovery
Every blocking call can lose its connection — a deploy, a proxy timeout, a crashed process. Recovery is built into the contract:- Create dropped? Repeat the same
POSTwith the sameIdempotency-Key. The replay re-attaches to the in-flight application and resumes blocking on the same wait. (A different body with a reused key is409 idempotency_key_reuse.) - Answers dropped? Repeat the same
POST. Answers are accepted exactly once per (step, correction round); a duplicate post attaches to the in-flight wait and its payload is ignored. - Got a
202? The server’s hold budget (~9 minutes) expired while the application was still working. The body is a snapshot; continue withGET /api/auto-apply/applications/{id}?wait_seconds=540, which long-polls until the application is answerable or terminal.
6. Local development
Run your integration anywhere — localhost, CI, a notebook. Nothing about the loop requires inbound connectivity. The one exception:file field answers (resumes) are supplied as a public
HTTPS URL that Jobo downloads. Host the file anywhere Jobo can reach — object
storage with a signed URL works well. A localhost URL is rejected with
unsafe_file_url.
7. Cancel
POST /api/auto-apply/applications/{id}/cancel requests cancellation at any
point. Queued applications cancel immediately; executing ones stop at the next
safe checkpoint. A submission the ATS already confirmed wins the race — the
application ends submitted, with cancel_requested: true recording the
attempt.
