Skip to main content
This walkthrough takes you from a resume file to a submitted job application using nothing but curl. You need an API key sent in the X-Api-Key header; the base URL is https://connect.jobo.world.
Currently unavailable. Every Auto Apply endpoint returns 503 Service Unavailable while the service is paused, so these calls will not succeed yet. The walkthrough documents the API as it will behave once re-enabled.
export JOBO_KEY="your-api-key"
export BASE="https://connect.jobo.world"
1

Import a resume

Upload the resume file as multipart form data (field name file). AI extracts contact details, links, work experience, education, and memories — plain-language facts used later to answer screening questions.
curl -X POST "$BASE/api/auto-apply/profiles/import" \
  -H "X-Api-Key: $JOBO_KEY" \
  -F "file=@ada-lovelace.pdf"
The response is 202 Accepted — the import runs in the background:
{
  "profile_id": "8c5e6d0a-9f2b-4c1e-b7a3-2f4d5e6a7b8c",
  "status": "importing"
}
Accepted formats: PDF, DOCX, TXT, RTF, MD. Max 10 MB (413 if larger, 415 for other types).
2

Poll until the profile is ready

Poll Get a profile until status leaves importing — typically 10–30 seconds. Polling is free.
curl "$BASE/api/auto-apply/profiles/8c5e6d0a-9f2b-4c1e-b7a3-2f4d5e6a7b8c" \
  -H "X-Api-Key: $JOBO_KEY"
{
  "id": "8c5e6d0a-9f2b-4c1e-b7a3-2f4d5e6a7b8c",
  "name": "Default",
  "status": "ready",
  "contact": { "first_name": "Ada", "last_name": "Lovelace", "email": "ada@example.com", "phone": "+1 415 555 0100" },
  "links": { "linkedin": "https://www.linkedin.com/in/ada-lovelace", "github": "https://github.com/adalovelace" },
  "work_experience": [ { "company": "Analytical Engines Ltd", "title": "Senior Backend Engineer", "start_date": "2021-03", "is_current": true } ],
  "education": [ { "school": "University of London", "degree": "BSc", "field_of_study": "Mathematics", "end_date": "2020" } ],
  "memories": [ "8 years of backend engineering experience", "Key skills: Go, Kubernetes, PostgreSQL" ],
  "resume": { "file_name": "ada-lovelace.pdf", "content_type": "application/pdf", "size_bytes": 182333 }
}
If status comes back import_failed, import_error says why — fix the profile with a PATCH (which flips it back to ready) or import again.
3

Add what a resume can't contain (optional)

Eligibility, preferences, and voluntary self-identification are never parsed from the resume — PATCH them in. Every section present in the body replaces that whole section; absent sections are untouched.
curl -X PATCH "$BASE/api/auto-apply/profiles/8c5e6d0a-9f2b-4c1e-b7a3-2f4d5e6a7b8c" \
  -H "X-Api-Key: $JOBO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "eligibility": {
      "work_authorized_countries": ["United States"],
      "requires_sponsorship": false
    },
    "preferences": {
      "salary_expectation": { "amount": 120000, "currency": "USD", "period": "year" },
      "remote_preference": "remote",
      "willing_to_relocate": true
    }
  }'
4

Submit an application

One POST with the profile and a job URL — this is a billed call ($0.20). The response is 202 Accepted with the application in running state; the browser run continues server-side.
curl -X POST "$BASE/api/auto-apply/applications" \
  -H "X-Api-Key: $JOBO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profile_id": "8c5e6d0a-9f2b-4c1e-b7a3-2f4d5e6a7b8c",
    "job_url": "https://boards.greenhouse.io/acme/jobs/4567890"
  }'
{
  "id": "f3b9c2d1-7e8a-4b5c-9d0e-1f2a3b4c5d6e",
  "profile_id": "8c5e6d0a-9f2b-4c1e-b7a3-2f4d5e6a7b8c",
  "job_url": "https://boards.greenhouse.io/acme/jobs/4567890",
  "status": "running",
  "step_log": [],
  "created_at": "2026-07-05T10:15:00Z",
  "completed_at": null
}
The profile must have status = ready — a profile that is still importing (or whose import failed) returns 409.
5

Poll for the outcome

Poll Get an application — free — until status becomes submitted or failed. A typical run takes 1–5 minutes.
curl "$BASE/api/auto-apply/applications/f3b9c2d1-7e8a-4b5c-9d0e-1f2a3b4c5d6e" \
  -H "X-Api-Key: $JOBO_KEY"
{
  "id": "f3b9c2d1-7e8a-4b5c-9d0e-1f2a3b4c5d6e",
  "status": "submitted",
  "provider_id": "greenhouse",
  "provider_name": "Greenhouse",
  "steps_completed": 3,
  "fields_filled": 24,
  "duration_ms": 93000,
  "failure_reason": null,
  "error": null,
  "step_log": [
    { "step": 1, "action": "navigate",    "fields_count": 0,  "status": "ok", "error": null, "timestamp": "2026-07-05T10:15:05Z" },
    { "step": 2, "action": "fill_fields", "fields_count": 24, "status": "ok", "error": null, "timestamp": "2026-07-05T10:16:12Z",
      "fields": [
        { "field_id": "f0:first_name", "label": "First name", "type": "text", "required": true, "value": "John", "status": "filled" }
      ]
    },
    { "step": 3, "action": "submit",      "fields_count": 0,  "status": "ok", "error": null, "timestamp": "2026-07-05T10:16:33Z" }
  ],
  "completed_at": "2026-07-05T10:16:38Z"
}
On failed, failure_reason carries a machine-readable cause (login_required, captcha_required, unsupported_provider, …) and the step_log shows exactly where the run stopped. See the failure reasons table.

Alternative: create a profile from JSON

If you already have structured applicant data, skip the import and create the profile directly. contact.first_name, contact.last_name, and contact.email are required; any omitted section starts empty.
curl -X POST "$BASE/api/auto-apply/profiles" \
  -H "X-Api-Key: $JOBO_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Default",
    "contact": {
      "first_name": "Ada",
      "last_name": "Lovelace",
      "email": "ada@example.com",
      "phone": "+1 415 555 0100"
    },
    "location": { "city": "Austin", "state": "TX", "country": "United States" },
    "links": { "linkedin": "https://www.linkedin.com/in/ada-lovelace" },
    "work_experience": [
      {
        "company": "Analytical Engines Ltd",
        "title": "Senior Backend Engineer",
        "start_date": "2021-03",
        "is_current": true,
        "description": "Led the payments platform team."
      }
    ],
    "education": [
      { "school": "University of London", "degree": "BSc", "field_of_study": "Mathematics", "end_date": "2020" }
    ],
    "memories": ["8 years of backend engineering experience"]
  }'
A JSON-created profile has no resume file yet — attach one so forms with a required resume field can be completed. The same call replaces an existing file at any time:
curl -X PUT "$BASE/api/auto-apply/profiles/8c5e6d0a-9f2b-4c1e-b7a3-2f4d5e6a7b8c/resume" \
  -H "X-Api-Key: $JOBO_KEY" \
  -F "file=@ada-lovelace-v2.pdf"
Uploading a resume file does not re-run the AI import — use Import a profile from a resume when you want profile data rebuilt from the file.

Next steps

Profile schema

Every profile section, field, constraint, and enum.

Interactive sessions

Step through forms field by field when you want full control over every answer.