Every aggregator lives or dies by its source, and most niches offer only bad choices, scraping fragile pages or paying for feeds. The federal jobs niche is the exception that decided this whole project, the United States government runs USAJOBS, an official, documented, free API of every federal opening, and this post is that choice plus the real mechanics of calling it correctly, because its authentication trips almost everyone once.
The API lives at data.usajobs.gov, and it authenticates through headers, not URL keys, three of them, and all three matter:
function jab_source_headers() {
$s = get_option('jab_settings', array());
return array(
'Host' => 'data.usajobs.gov',
'User-Agent' => $s['api_email'], // the email you registered
'Authorization-Key' => $s['api_key'], // the key USAJOBS issued
);
}
$url = 'https://data.usajobs.gov/api/search?Keyword=army&ResultsPerPage=100';
$response = wp_remote_get($url, array('timeout' => 30, 'headers' => jab_source_headers()));
The quirk to burn in, USAJOBS wants your registered email in the User-Agent header, not a browser string, and the key in Authorization-Key, and requests missing either come back denied in ways that look like mysterious failures. Both values live in the plugin’s settings, entered on an admin screen, never hardcoded, the same key hygiene as the Stripe work, and one real bug from this build is worth recording, my settings fallback used isset instead of checking for empty strings, so a blank saved key passed the isset test and every request failed politely, the fix was the stricter check, if (!empty($s[‘api_key’])), empty catches both absent and blank, which is what credential checks actually mean.
The response is JSON with the jobs nested under SearchResult and each position inside a MatchedObjectDescriptor, names you learn quickly because the whole importer maps from them. And the strategic point deserves its own paragraph, an official API is a different life from scraping. The format is documented and versioned rather than whatever the HTML happens to be this week, the data is legally and explicitly offered for reuse, and the maintenance burden of the silver-site scraper era, parsers breaking with every redesign, simply does not exist here. When choosing a niche for a data-driven site, the existence of an official API is not a nice-to-have, it is close to the whole decision.
A few things people ask me about this
Why does my USAJOBS request return nothing or a denial? Almost always headers, the registered email must be the User-Agent and the key must be in Authorization-Key. URL parameters alone do not authenticate you.
Why check credentials with empty instead of isset? Because a saved-but-blank field passes isset and then fails every request mysteriously. empty treats absent and blank the same, which is what a credential check means.
Next
With jobs flowing in, they needed proper homes, and the post type grew its taxonomies, department, job type, location, along with a bug about flags that cost me an evening. That structure is the next post.
