Authentication
Create a key in the dashboard and send it as a bearer token (or in an X-API-Key header). Keys are secrets: call the API from your server, never from a browser or an app. The base URL is https://findyourcareer.io/api/v1.
curl "https://findyourcareer.io/api/v1/jobs?title=data+engineer&country=de&work_arrangement=remote&limit=2" \
-H "Authorization: Bearer $FYC_API_KEY"Endpoints
| Endpoint | What it does | Credits |
|---|---|---|
| GET /jobs | Search jobs, newest first. | 1 per job not yet received this month |
| GET /jobs/{id} | One job with its full description. 404 once it has closed. | 1, or 0 if already received this month |
| GET /changes | Ids of jobs added, updated or closed since your last call. Growth and larger plans. | None |
| GET /usage | Your plan, this month's usage and your request limits. | None |
| GET /filters | Every search parameter and the country codes. | None |
GET /jobs
All parameters are optional and combine with AND. Without any, you get the newest jobs of the whole dataset. Booleans are true or false.
| Parameter | Meaning |
|---|---|
| title | Job title to match, e.g. "Backend Engineer". Up to five alternatives separated by OR. |
| exclude_title | Drop jobs whose title contains any of these words, separated by commas or OR. |
| query | Keyword to match in the job title or company name. |
| company | Company name to match. |
| location | City, region or state the job is in, e.g. "Berlin". |
| country | Two-letter ISO 3166-1 code of the job's country, e.g. "de". |
| work_arrangement | remote, hybrid or onsite. |
| worldwide | Only remote jobs open to candidates anywhere in the world. |
| include_worldwide | With a country or location, also include remote jobs open worldwide. |
| include_eu | With a country, also include jobs in every EU member state. |
| eligible_state | Only remote jobs that list this state as one the candidate may live in, as an ISO 3166-2 code such as "US-FL". |
| include_nationwide | With eligible_state, also include jobs open to the whole country that list no states. |
| employment_type | Full-time, Part-time, Contract, Internship or Temporary. |
| job_level | entry, junior, mid, senior or lead. |
| experience | Years of experience the candidate has (0-2, 2-5, 5-10, 10+); jobs asking for more are left out. |
| skill | A skill the job lists, e.g. "Python". |
| language | A working language the job requires, e.g. "German". |
| visa_sponsorship | Only jobs that offer visa sponsorship. |
| no_clearance | Leave out jobs that require a security clearance. |
| require_salary | Only jobs that state a salary. |
| salary_min | Minimum yearly salary in salary_currency. |
| salary_currency | EUR or USD; required with salary_min. |
| posted_within_hours | Only jobs posted within this many hours, e.g. 24. |
| created_after | Only jobs we first saw after this moment (ISO 8601). Use it to pick up what is new since your last sync. |
| hide_ghost | Leave out likely ghost jobs (ghost_score of 50 or higher). |
| hide_seen_before | Leave out recycled postings: jobs first seen more than an hour before their posting date. |
| hide_past_deadline | Leave out jobs whose application deadline has passed. |
| include_description | Return the full description with every job instead of only the 500-character excerpt. |
| limit | Jobs per page, 1 to 100. |
| cursor | next_cursor of the previous page, with the same filters. |
Paging. A page holds 25 jobs by default and at most 100. While has_more is true, repeat the request with the same filters and cursor set to next_cursor. A search is a snapshot: later pages never include jobs posted after the first page was made.
Staying in sync. To pick up what is new, search with created_after set to the moment of your previous run. On Growth and larger plans, GET /changes also tells you which jobs closed.
{
"jobs": [
{
"id": "cmh2x9k4t00a1",
"title": "Senior Data Engineer",
"company": "Example GmbH",
"location": "Berlin, Germany",
"country": "de",
"work_arrangement": "remote",
"remote_scope": "country",
"eligible_states": [],
"employment_type": "Full-time",
"job_level": "senior",
"skills": ["Python", "Airflow", "dbt"],
"languages": ["German", "English"],
"visa_sponsorship": false,
"salary": { "min": "85000", "max": "105000", "currency": "EUR", "period": "year" },
"posted_at": "2026-11-08T07:12:00.000Z",
"first_seen_at": "2026-11-08T08:03:41.000Z",
"republish_count": 0,
"ghost_score": 0,
"ghost_level": "low",
"source": "greenhouse",
"apply_url": "https://boards.greenhouse.io/example/jobs/1234567",
"url": "https://findyourcareer.io/jobs/cmh2x9k4t00a1"
}
],
"returned_count": 1,
"new_credits_charged": 1,
"has_more": true,
"next_cursor": "eyJwIjoiMjAyNi0xMS0wOFQwNzoxMjowMC4wMDBaIi...",
"usage": { "plan": "growth", "limit": 100000, "used": 18422, "remaining": 81578 }
}Job fields
Null means the posting does not say; nothing is guessed.
| Field | What it is |
|---|---|
| id | Stable id of the job. The same job keeps its id for as long as it is listed. |
| title, company | As the employer wrote them. |
| company_website, company_logo | The employer's site and logo, where known. |
| location, city, country | Where the job is. country is a two-letter ISO code. |
| additional_locations | Other places the same posting is open in. |
| work_arrangement | remote, hybrid or onsite. |
| remote_scope | Who may apply to a remote job: worldwide, region or country. Null when the posting does not say. |
| eligible_states | The states a remote job requires you to live in, as ISO 3166-2 codes such as US-FL. |
| employment_type, job_level | Full-time, contract and so on; entry to lead. |
| min_years_experience, max_years_experience | Years of experience the posting asks for. |
| skills, languages | Skills the job lists and the working languages it requires. |
| visa_sponsorship, security_clearance | True, false, or null when the posting does not say. |
| salary | min, max, currency and period, as the employer stated them. |
| benefits | Benefits named in the posting. |
| posted_at, first_seen_at, last_checked_at | When the employer posted it, when we first saw it and when we last confirmed it is still listed. |
| application_deadline | Last day to apply, when the posting states one. |
| republish_count | How often the employer re-posted the job. |
| ghost_score, ghost_level | 0 to 100: how likely the job is a ghost job, from how long it has been open, re-posts and refreshed dates. 50 and up is high. |
| source | The applicant tracking system or feed the job came from. |
| apply_url | The employer's own application page. |
| excerpt, description | The first 500 characters, and the full text on request. |
| url | The job's page on findyourcareer.io. |
GET /changes
Call it once without parameters to get your starting position in next_after. From then on pass that value as after: you get the ids that changed since, each live (new or updated; fetch it with GET /jobs/{id}) or removed (closed).
| Parameter | Meaning |
|---|---|
| after | next_after of the previous page. Leave it out on the first call to get the current position. |
| limit | Changes per page, 1 to 1000. |
Plans and limits
A credit is one unique job per calendar month (UTC). The allowance resets on the first of the month. Requests that return no new jobs cost nothing.
| Plan | Jobs | Requests per second | Job requests at once | Changes feed |
|---|---|---|---|---|
| Test key | 500 in total | 1 | 1 | No |
| Starter | 25,000 a month | 2 | 2 | No |
| Growth | 100,000 a month | 5 | 4 | Yes |
| Scale | 400,000 a month | 15 | 8 | Yes |
| Enterprise | Custom | Custom | Custom | Yes |
When the allowance is used up, a page is cut short (truncated_by_quota) and jobs you already received stay available. Switch on extra jobs in the dashboard to continue at your plan's rate per 1,000; they appear on your next invoice.
Errors
An error is a JSON body { "error": { "code", "message" } } with the HTTP status below. Rate-limit responses also carry a Retry-After header.
| Code | Status | Meaning |
|---|---|---|
| INVALID_PARAMETERS | 400 | A parameter is unknown or has a wrong value. issues names each one. |
| INVALID_CURSOR | 400 | The cursor is malformed or was made with other filters. |
| SEARCH_TOO_BROAD | 400 | The search took too long. Narrow it; retrying unchanged will not help. |
| UNAUTHORIZED | 401 | The key is missing or not valid. |
| KEY_REVOKED | 401 | The key was revoked in the dashboard. |
| PAYMENT_REQUIRED | 402 | The last payment failed. Update the payment method. |
| QUOTA_EXCEEDED | 402 | The allowance is used up and extra jobs are off. The response carries usage and reset_at. |
| ACCOUNT_BLOCKED | 403 | API access is suspended for the account. |
| PLAN_REQUIRED | 403 | The endpoint is not part of the account's plan. |
| NOT_FOUND | 404 | The job is not listed (any more). |
| RATE_LIMITED | 429 | More requests per second than the plan allows. Wait retry_after_seconds. |
| TOO_MANY_CONCURRENT_REQUESTS | 429 | More job requests in flight than the plan allows. |
| SERVICE_UNAVAILABLE | 503 | A temporary problem on our side. Retry after retry_after_seconds. |
Using the data
You may show the jobs in your own product and link to the employer's application page. Reselling the data as a feed, dataset or competing API is not allowed. Read the API licence terms.