Help us shape the future of Go! Take the 2026 Go Developer Survey

carejobs

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 12 Imported by: 0

README

carejobs-go

Go client for the CareJobs.Now healthcare jobs API. Search open US healthcare jobs, see the pay employers post, and look up employers and states.

  • Free, no API key.
  • Standard library only. Go 1.24 or newer.
  • Context-aware methods, typed results, one *carejobs.Error type.
  • The same API is a remote MCP server at https://carejobs.now/api/mcp, so any MCP client can use it too.
  • Also a carejobs command line tool: see below.

Where the data comes from

CareJobs.Now is a free US healthcare job board. Its jobs are read daily from the career sites of US hospitals, health systems, clinics and care employers, and the pay is what each posting states (hourly rates before shift differentials and bonuses). Every job links to its page on CareJobs.Now, where the user applies. Data and docs: https://carejobs.now/data (CC BY 4.0, credit CareJobs.Now).

Install

go get github.com/yumaheymans/carejobs-go

Quick start

package main

import (
	"context"
	"fmt"
	"log"

	carejobs "github.com/yumaheymans/carejobs-go"
)

func main() {
	c := carejobs.NewClient()

	res, err := c.SearchJobs(context.Background(), carejobs.SearchParams{
		Kind:  carejobs.KindNurses,
		State: "TX",
		Query: "ICU",
		Limit: 5,
	})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(res.Total, "jobs match")
	for _, job := range res.Jobs {
		fmt.Println(job.Title, "|", job.Employer, "|", job.Location, "|", job.URL)
	}

	// Every result also carries the server's readable summary:
	fmt.Println(res.Text)
}

A runnable version is in examples/search: go run ./examples/search OH.

Client

c := carejobs.NewClient(
	carejobs.WithBaseURL("https://carejobs.now"),     // default
	carejobs.WithHTTPClient(&http.Client{}),          // default: a client with no timeout of its own
	carejobs.WithUserAgent("my-app/1.0"),             // default: "carejobs-go/<version>"
)

A Client is safe for concurrent use.

Method What it answers Result
SearchJobs(ctx, SearchParams) Open jobs by query, kind, employer, state, remote, minimum hourly pay, sort, limit *SearchResult
Pay(ctx, PayParams) Posted hourly pay: every kind, one kind, one employer, or both *PayResult
JobMarket(ctx) How many jobs are open, by kind, state and employer *JobMarket
JobsByState(ctx, StateParams) Every state, one state, or one kind of job in one state *StateResult
Employers(ctx, EmployerListParams) The employers, AI-training programs and job boards the site reads *EmployerList
Employer(ctx, slug) One employer by slug or name *Employer
Tools(ctx) The server's tools with their input schemas []Tool
Call(ctx, name, args) Any tool, undecoded *RawResult

Every parameter is optional (the zero value leaves a filter off), and every result has a Text field with the plain-text summary the server writes.

Pay and JobsByState return one struct for answers of different shapes. The documentation of PayResult and StateResult lists which fields each question fills. Where the API sends null for "none", the Go field holds its zero value (an empty string, 0, or a nil pointer or slice): PayResult.Pay is nil when too few of an employer's jobs post an hourly rate to measure, and PayText then says how the employer posts pay.

pay, err := c.Pay(ctx, carejobs.PayParams{Kind: carejobs.KindNurses})
if err != nil {
	log.Fatal(err)
}
fmt.Printf("median $%.0f/hr, typical $%.0f to $%.0f/hr\n",
	pay.Pay.Median, pay.Pay.TypicalLow, pay.Pay.TypicalHigh)
for _, e := range pay.BestPaying {
	fmt.Println(e.Name, e.Median)
}

ohio, err := c.JobsByState(ctx, carejobs.StateParams{State: "OH", Kind: carejobs.KindNursingAssistants})
Kinds

carejobs.Kinds lists the 17 kinds of job, each with a constant: KindNurses, KindNursePractitioners, KindPhysicians, KindNursingAssistants, KindCaregivers, KindTherapyRehab, KindMentalHealth, KindPharmacy, KindImaging, KindLab, KindSurgicalTechs, KindEMTsParamedics, KindMedicalAssistants, KindDental, KindAdmin, KindAlliedHealth, KindAITraining. Sort, EmployerType and Care have constants too.

Errors

Every error is an *carejobs.Error:

var apiErr *carejobs.Error
if errors.As(err, &apiErr) {
	switch apiErr.Code {
	case carejobs.CodeTool: // the server ran the tool and said no: apiErr.Message has its text
	case carejobs.CodeRPC: // a JSON-RPC error (apiErr.RPCCode)
	case carejobs.CodeHTTP: // a non-2xx status (apiErr.Status)
	case carejobs.CodeTimeout, carejobs.CodeCanceled, carejobs.CodeNetwork:
	case carejobs.CodeProtocol: // the answer was not what MCP promises
	}
}

errors.Is(err, context.DeadlineExceeded) and errors.Is(err, context.Canceled) work.

Timeouts

Without WithHTTPClient, a call gives up after 15 seconds unless its context has a deadline of its own, in which case the context decides. The server answers a query it has not seen before in up to about 20 seconds, and repeats of it in a fraction of a second, so give a first call a longer deadline:

ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
res, err := c.SearchJobs(ctx, params)

With WithHTTPClient, your client and the context decide.

Command line

The module ships a carejobs command (standard library only, no key, Go 1.24 or newer to build it):

go install github.com/yumaheymans/carejobs-go/cmd/carejobs@latest

Or download a ready-made binary from the releases page. Each release has an archive per system, carejobs_<version>_<os>_<arch>.zip for Windows and carejobs_<version>_<os>_<arch>.tar.gz for macOS and Linux (amd64 and arm64 each), and a checksums.txt with their SHA-256. Unpack one and put carejobs (carejobs.exe on Windows) in a folder on your PATH:

curl -LO https://github.com/yumaheymans/carejobs-go/releases/download/v1.1.0/carejobs_1.1.0_darwin_arm64.tar.gz
tar -xzf carejobs_1.1.0_darwin_arm64.tar.gz
./carejobs --version

The binaries are not code-signed. A browser download may therefore trigger a macOS Gatekeeper or Windows SmartScreen warning; curl and go install do not.

carejobs search "icu nurse" --state TX --limit 5
carejobs pay --kind nurses
carejobs market
carejobs state TX
carejobs employers --query kaiser
carejobs employer kaiser-permanente
carejobs tools
Command Options
search [words] --kind --employer --state --remote --min-hourly USD --sort --limit --query
pay --kind --employer
market
state [STATE] --kind --limit
employers [words] --query --type --care --state --kind --limit
employer SLUG
tools

Options for every command: --json prints the raw data as JSON instead of the readable summary, --base-url, --timeout SECONDS (default 60, because the first query of its kind can take up to about 25 seconds while the server wakes its database), --help, --version. Options and words can come in any order.

--kind takes the exact kinds above and common short names (rn, cna, np, doctor, registered-nurse and a few more). --sort is mixed, newest or highest_pay, --type is employer, ai-program or job-board. The exit code is 0 on success, 1 when the API answers with an error or cannot be reached, and 2 for bad usage. The npm and Python packages ship the same command.

Tests

go test ./...                        # unit tests, offline, on recorded answers in testdata/ (the command line tool too)
go test -tags live -run Live -v ./... # the same questions against the real API

The unit tests replay real answers recorded from the live API (long lists are trimmed). A strict-decode test refuses any field that a recorded answer has and the structs do not, and the live test does the same against the live answers and also checks the Kind constants against the server's own list.

Releases

scripts/build-release.sh builds the archives of the command into dist/ (Windows, macOS and Linux, amd64 and arm64, with checksums.txt). Pushing a tag such as v1.1.0 runs the same script in .github/workflows/release.yml and attaches the archives to the GitHub release. The tag must match the Version constant in client.go.

License

MIT. See LICENSE.

Documentation

Overview

Package carejobs is a client for the CareJobs.Now healthcare jobs API.

CareJobs.Now (https://carejobs.now) is a free US healthcare job board. Its jobs are read daily from the career sites of US hospitals, health systems, clinics and care employers, and the pay is what each posting states. The API is a remote MCP server at https://carejobs.now/api/mcp: free, no key. This package speaks to it with the standard library only.

Create a Client and call its methods with a context:

c := carejobs.NewClient()

res, err := c.SearchJobs(ctx, carejobs.SearchParams{
	Kind:  carejobs.KindNurses,
	State: "TX",
	Query: "ICU",
	Limit: 5,
})
if err != nil {
	log.Fatal(err)
}
fmt.Println(res.Total, "jobs match")
for _, job := range res.Jobs {
	fmt.Println(job.Title, "|", job.Employer, "|", job.Location, "|", job.URL)
}

The methods are SearchJobs, Pay, JobMarket, JobsByState, Employers and Employer, one for each of the server's six tools. Tools lists the tools with their schemas, and Call runs any tool and returns the undecoded answer.

Every result carries Text, the plain-text summary the server writes, next to the typed data. Pay and JobsByState return one struct for answers of different shapes; the documentation of PayResult and StateResult says which fields each question fills.

Every error is an *Error. It tells a tool error (an unknown employer, an invalid kind) from a transport failure:

var apiErr *carejobs.Error
if errors.As(err, &apiErr) && apiErr.Code == carejobs.CodeTool {
	fmt.Println("the server said:", apiErr.Message)
}

The jobs link to their pages on CareJobs.Now, where the user applies. The pay figures are the hourly rates open jobs post (before shift differentials and bonuses), and a market rate is only given where at least three employers post one. Data: https://carejobs.now/data (CC BY 4.0, credit CareJobs.Now).

Index

Constants

View Source
const (
	// Version is the version of this module, sent in the default User-Agent.
	Version = "1.1.0"

	// DefaultBaseURL is the CareJobs.Now site; the MCP endpoint is
	// DefaultBaseURL + "/api/mcp".
	DefaultBaseURL = "https://carejobs.now"

	// DefaultTimeout is how long a call may take when the context carries no
	// deadline of its own. A context with a deadline overrides it, so pass a
	// longer one for a slow query: the server answers a query it has not seen
	// before in up to about 20 seconds, then repeats of it in a fraction of one.
	DefaultTimeout = 15 * time.Second
)

Variables

Kinds lists every Kind constant, in the order the API documents them.

Functions

This section is empty.

Types

type Care

type Care string

Care is a kind of care, the `care` filter of Employers.

const (
	CareHealthSystem      Care = "health-system"
	CareChildrensHospital Care = "childrens-hospital"
	CareOutpatient        Care = "outpatient"
	CareSpecialty         Care = "specialty-care"
	CareBehavioralHealth  Care = "behavioral-health"
	CareAutism            Care = "autism-care"
	CareHomeCare          Care = "home-care"
	CareSeniorCare        Care = "senior-care"
	CareRehab             Care = "rehab"
	CareDental            Care = "dental"
	CarePharmacyRetail    Care = "pharmacy-retail"
	CareKidney            Care = "kidney-care"
	CareLabsImaging       Care = "labs-imaging"
	CareTelehealth        Care = "telehealth"
	CareStaffing          Care = "staffing"
	CareAITraining        Care = "ai-training"
	CareJobBoards         Care = "job-boards"
)

The kinds of care an employer list can be filtered by.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client calls the CareJobs.Now healthcare jobs API (a remote MCP server, no key needed). Create one with NewClient. A Client is safe for concurrent use.

func NewClient

func NewClient(opts ...Option) *Client

NewClient returns a Client for the live API, adjusted by opts. Without WithHTTPClient, a call gives up after DefaultTimeout (15 seconds) unless its context has a deadline.

func (*Client) Call

func (c *Client) Call(ctx context.Context, name string, args any) (*RawResult, error)

Call runs any tool by name with args (a struct, a map or nil) and returns the undecoded answer. The typed methods are built on it; use it for a tool or a field this module does not know yet.

func (*Client) Employer

func (c *Client) Employer(ctx context.Context, slug string) (*Employer, error)

Employer returns one employer, AI-training program or job board, by slug (for example "cvs-health") or by name. Employers finds the slugs.

func (*Client) Employers

func (c *Client) Employers(ctx context.Context, p EmployerListParams) (*EmployerList, error)

Employers lists the employers, AI-training programs and job boards whose jobs CareJobs.Now reads, most open jobs first.

func (*Client) JobMarket

func (c *Client) JobMarket(ctx context.Context) (*JobMarket, error)

JobMarket reports how many healthcare jobs are open right now and how they split by kind of job, US state and employer.

func (*Client) JobsByState

func (c *Client) JobsByState(ctx context.Context, p StateParams) (*StateResult, error)

JobsByState reports open jobs by US state. See StateParams for how the parameters choose the answer and StateResult for which fields each answer fills.

func (*Client) Pay

func (c *Client) Pay(ctx context.Context, p PayParams) (*PayResult, error)

Pay measures what healthcare jobs post as hourly pay. See PayParams for how the parameters choose the answer and PayResult for which fields each answer fills.

func (*Client) SearchJobs

func (c *Client) SearchJobs(ctx context.Context, p SearchParams) (*SearchResult, error)

SearchJobs searches the open healthcare jobs. Every filter is optional.

func (*Client) Tools

func (c *Client) Tools(ctx context.Context) ([]Tool, error)

Tools returns the tools the server offers, with their input schemas.

type Employer

type Employer struct {
	Slug     string       `json:"slug"`
	Name     string       `json:"name"`
	Type     EmployerType `json:"type"`
	Model    string       `json:"model"`
	Care     string       `json:"care"`
	HQ       string       `json:"hq"`
	States   []string     `json:"states"`
	OpenJobs int          `json:"open_jobs"`
	// OpenByKind is its open jobs by kind of job.
	OpenByKind []EmployerKind `json:"open_by_kind"`
	// Pay is the pay its jobs post. Nil when too few post an hourly rate;
	// PayText then says how it posts pay.
	Pay     *PayStats `json:"pay"`
	PayText string    `json:"pay_text"`
	// Newest are its newest open jobs.
	Newest []Job `json:"newest"`
	// BestPaid are its best-paid open jobs.
	BestPaid []Job `json:"best_paid"`
	// URL is its page on CareJobs.Now.
	URL string `json:"url"`
	// JobsURL lists every open job of it on CareJobs.Now. Empty when it has none.
	JobsURL string `json:"jobs_url"`
	// CareersURL is its own careers site. Empty when not known.
	CareersURL string `json:"careers_url"`
	// Text is the server's plain-text summary.
	Text string `json:"text"`
}

Employer is the answer of Client.Employer: one employer, AI-training program or job board.

type EmployerKind

type EmployerKind struct {
	Kind     Kind   `json:"kind"`
	Label    string `json:"label"`
	OpenJobs int    `json:"open_jobs"`
	// Pay is nil when too few of these jobs post an hourly rate.
	Pay *PayStats `json:"pay"`
}

EmployerKind is an employer's open jobs of one kind, with the pay they post.

type EmployerList

type EmployerList struct {
	// Total is how many entries match (all of them, not only those returned).
	Total int `json:"total"`
	// Entries are the entries returned, most open jobs first.
	Entries []EmployerSummary `json:"entries"`
	// Text is the server's plain-text summary.
	Text string `json:"text"`
}

EmployerList is the answer of Employers.

type EmployerListParams

type EmployerListParams struct {
	// Query is part of the name, for example "Kaiser", "children" or "dialysis".
	Query string `json:"query,omitempty"`
	// Type says whether to list employers (the default), AI-training programs or
	// job boards.
	Type EmployerType `json:"type,omitempty"`
	// Care is a kind of care, for example CareHomeCare.
	Care Care `json:"care,omitempty"`
	// State keeps employers with open jobs in this US state.
	State string `json:"state,omitempty"`
	// Kind keeps employers with open jobs of this kind.
	Kind Kind `json:"kind,omitempty"`
	// Limit is how many to return (1 to 100, server default 20).
	Limit int `json:"limit,omitempty"`
}

EmployerListParams filters Employers. Every field is optional.

type EmployerPay

type EmployerPay struct {
	Slug string `json:"slug"`
	Name string `json:"name"`
	PayStats
}

EmployerPay is the pay one employer posts, as listed in BestPaying.

type EmployerSummary

type EmployerSummary struct {
	// Slug is the identifier other calls take, for example "cvs-health".
	Slug string `json:"slug"`
	Name string `json:"name"`
	// Type says whether it is an employer, an AI-training program or a job board.
	Type EmployerType `json:"type"`
	// Model is the business model, for example "Pharmacy and retail health".
	Model string `json:"model"`
	// Care is the label of the kind of care.
	Care string `json:"care"`
	// HQ is the headquarters. Empty when not known.
	HQ string `json:"hq"`
	// States are the two-letter codes of the states it hires in.
	States []string `json:"states"`
	// OpenJobs is how many jobs it has open.
	OpenJobs int `json:"open_jobs"`
	// PostedMedianHourly is the median of the hourly rates its open jobs post.
	// 0 when too few post one.
	PostedMedianHourly float64 `json:"posted_median_hourly"`
	// URL is its page on CareJobs.Now.
	URL string `json:"url"`
}

EmployerSummary is one entry of the employer list.

type EmployerType

type EmployerType string

EmployerType says what an employer list entry is.

const (
	EmployerTypeEmployer  EmployerType = "employer"   // a hospital, clinic or care company
	EmployerTypeAIProgram EmployerType = "ai-program" // a program paying health professionals for remote AI work
	EmployerTypeJobBoard  EmployerType = "job-board"  // a source of other employers' jobs
)

The three types of entry in the employer list.

type Error

type Error struct {
	// Code says where the error came from.
	Code ErrorCode
	// Message is the server's text for a CodeTool, CodeRPC or CodeHTTP error,
	// and a description of what went wrong otherwise.
	Message string
	// Tool is the tool that was called, when there was one.
	Tool string
	// Status is the HTTP status of a CodeHTTP error.
	Status int
	// RPCCode is the JSON-RPC error code of a CodeRPC error.
	RPCCode int
	// Err is the underlying cause (a network or decoding error), if any.
	Err error
}

Error is the error type every Client method returns. Use errors.As to read it:

var apiErr *carejobs.Error
if errors.As(err, &apiErr) && apiErr.Code == carejobs.CodeTool {
	fmt.Println("the server said:", apiErr.Message)
}

Unwrap exposes the underlying cause, so errors.Is(err, context.DeadlineExceeded) works for a CodeTimeout error.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the underlying cause, if any.

type ErrorCode

type ErrorCode string

ErrorCode says where an Error came from.

const (
	// CodeTool: the server ran the tool and answered with an error, for example
	// an unknown employer or an invalid kind. Message holds the server's text.
	CodeTool ErrorCode = "tool"
	// CodeRPC: a JSON-RPC error (unknown tool, malformed request). RPCCode is set.
	CodeRPC ErrorCode = "rpc"
	// CodeHTTP: a non-2xx HTTP status. Status is set.
	CodeHTTP ErrorCode = "http"
	// CodeNetwork: the request never completed (DNS, connection reset, and so on).
	CodeNetwork ErrorCode = "network"
	// CodeTimeout: no answer before the context deadline or the HTTP client timeout.
	CodeTimeout ErrorCode = "timeout"
	// CodeCanceled: the context was canceled before the answer arrived.
	CodeCanceled ErrorCode = "canceled"
	// CodeProtocol: the answer was not the shape the MCP protocol promises.
	CodeProtocol ErrorCode = "protocol"
)

type Hirer

type Hirer struct {
	// Key is the employer's slug.
	Key  string `json:"key"`
	Jobs int    `json:"jobs"`
}

Hirer is an employer hiring in a state.

type Job

type Job struct {
	Title    string `json:"title"`
	Employer string `json:"employer"`
	// Via names the job board the job was read through, when it is another
	// employer's job. Empty for a job read from the employer's own career site.
	Via string `json:"via"`
	// Kind is the label of the kind of job, for example "Nurses" or "Doctors".
	Kind string `json:"kind"`
	// Pay is the posted pay as text (for example "$42.43-$86.19/hr" or
	// "$80,000.00 - $95,000.00/year"). Empty when the posting states none. For
	// a posting with no rate the server may give the typical pay of its employer
	// and kind instead, and then says in the text that it is not a rate the
	// posting states.
	Pay string `json:"pay"`
	// Schedule lists the job's schedule tags, for example "Full-time".
	Schedule []string `json:"schedule"`
	// Facility is the facility named in the posting, when it names one.
	Facility string `json:"facility"`
	// Location is the place of the job. Empty for remote or placeless jobs.
	Location string `json:"location"`
	// Listed is the ISO date (YYYY-MM-DD) the job was first listed.
	Listed string `json:"listed"`
	// URL is the job's page on CareJobs.Now, where the user applies.
	URL string `json:"url"`
	// EmployerPage is the employer's page on CareJobs.Now, when it has one.
	EmployerPage string `json:"employer_page"`
}

Job is one open job as SearchJobs and Employer return it.

type JobMarket

type JobMarket struct {
	// OpenJobs is how many healthcare jobs are open right now.
	OpenJobs int `json:"open_jobs"`
	// SourcesLive is how many employers and job boards have one or more open jobs.
	SourcesLive int `json:"sources_live"`
	// NewLast7d is how many jobs were first listed in the last 7 days.
	NewLast7d int `json:"new_last_7d"`
	// NewPerWeek is how many jobs are listed per week. Nil while the server has
	// no figure.
	NewPerWeek *float64 `json:"new_per_week"`
	// Updated is the RFC 3339 timestamp (UTC) of the latest read of the career
	// sites. UpdatedAt parses it.
	Updated string `json:"updated"`
	// OpenByKind is the open jobs of every kind of job.
	OpenByKind []JobMarketKind `json:"open_by_kind"`
	// OpenByState is the open jobs of every US state.
	OpenByState []JobMarketState `json:"open_by_state"`
	// OpenByEmployer is the open jobs of every employer, most first.
	OpenByEmployer []JobMarketEmployer `json:"open_by_employer"`
	// Text is the server's plain-text summary.
	Text string `json:"text"`
}

JobMarket is the answer of Client.JobMarket: how many jobs are open and how they split by kind, state and employer.

func (*JobMarket) UpdatedAt

func (m *JobMarket) UpdatedAt() (time.Time, error)

UpdatedAt parses Updated.

type JobMarketEmployer

type JobMarketEmployer struct {
	Slug     string       `json:"slug"`
	Name     string       `json:"name"`
	Type     EmployerType `json:"type"`
	OpenJobs int          `json:"open_jobs"`
}

JobMarketEmployer is the open jobs of one employer, AI-training program or job board.

type JobMarketKind

type JobMarketKind struct {
	Slug     Kind   `json:"slug"`
	Label    string `json:"label"`
	OpenJobs int    `json:"open_jobs"`
}

JobMarketKind is the open jobs of one kind of job.

type JobMarketState

type JobMarketState struct {
	Code     string `json:"code"`
	Name     string `json:"name"`
	OpenJobs int    `json:"open_jobs"`
	URL      string `json:"url"`
}

JobMarketState is the open jobs of one US state.

type Kind

type Kind string

Kind is a kind of healthcare job, the `kind` filter of the API. The slugs are the ones the live tools/list answer allows; a test compares them with the server so drift is caught.

Results decode a kind into a plain Kind, so a slug the server adds later still arrives as a value (it just has no constant here yet).

const (
	KindNurses             Kind = "nurses"              // Registered nurses and LPNs
	KindNursePractitioners Kind = "nurse-practitioners" // NPs and PAs
	KindPhysicians         Kind = "physicians"          // Doctors
	KindNursingAssistants  Kind = "nursing-assistants"  // CNAs and patient care techs
	KindCaregivers         Kind = "caregivers"          // Caregivers and home health aides
	KindTherapyRehab       Kind = "therapy-rehab"       // Physical, occupational, speech and respiratory therapy
	KindMentalHealth       Kind = "mental-health"       // Mental health and social work
	KindPharmacy           Kind = "pharmacy"            // Pharmacists and pharmacy techs
	KindImaging            Kind = "imaging"             // Radiology and imaging techs
	KindLab                Kind = "lab"                 // Lab
	KindSurgicalTechs      Kind = "surgical-techs"      // Surgical techs
	KindEMTsParamedics     Kind = "emts-paramedics"     // EMS
	KindMedicalAssistants  Kind = "medical-assistants"  // Medical assistants
	KindDental             Kind = "dental"              // Dental
	KindAdmin              Kind = "admin"               // Front desk and admin
	KindAlliedHealth       Kind = "allied-health"       // Allied health
	KindAITraining         Kind = "ai-training"         // AI training for health professionals
)

The 17 kinds of job.

func (Kind) Valid

func (k Kind) Valid() bool

Valid reports whether k is one of the Kind constants.

type KindCount

type KindCount struct {
	Kind     Kind   `json:"kind"`
	Label    string `json:"label"`
	OpenJobs int    `json:"open_jobs"`
	URL      string `json:"url"`
}

KindCount is the open jobs of one kind of job inside a state answer. URL is empty where the API sends none.

type KindPay

type KindPay struct {
	Kind  Kind   `json:"kind"`
	Label string `json:"label"`
	PayStats
}

KindPay is the pay of one kind of job. Label is set in the all-kinds answer and empty in an employer's by-kind list.

type Option

type Option func(*Client)

Option configures a Client.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL points the Client at another host than DefaultBaseURL (a mirror or a test server). A trailing slash is ignored.

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

WithHTTPClient makes the Client use h instead of its default HTTP client. The DefaultTimeout then no longer applies: h (its Timeout and Transport) and the context of each call decide how long a call may take. A nil h is ignored.

func WithUserAgent

func WithUserAgent(userAgent string) Option

WithUserAgent sets the User-Agent header. The default is "carejobs-go/" and the Version.

type PayParams

type PayParams struct {
	// Kind is one kind of job.
	Kind Kind `json:"kind,omitempty"`
	// Employer is an employer slug or name.
	Employer string `json:"employer,omitempty"`
}

PayParams selects what Pay measures. With both fields empty it covers every kind of job; Kind alone gives that job's pay and the employers posting the most for it; Employer alone gives that employer's pay overall and by kind; both give that employer's pay for that job.

type PayResult

type PayResult struct {
	// AsOf is the ISO date the figures were measured.
	AsOf string `json:"as_of"`

	// TypicalPayDefinition explains how TypicalLow and TypicalHigh are measured.
	TypicalPayDefinition string `json:"typical_pay_definition"`
	// Board is the pay across every open job (MarketRate is not set on it).
	Board *PayStats `json:"board"`
	// PayByKind is the pay of every kind of job.
	PayByKind []KindPay `json:"pay_by_kind"`
	// NoMarketRate lists the kinds without a market rate. The API sends it as an
	// array whose entries have not appeared yet, so they are kept undecoded.
	NoMarketRate []json.RawMessage `json:"no_market_rate"`

	// Kind is the kind of job the answer is about.
	Kind Kind `json:"kind"`
	// Employer is the employer's slug.
	Employer string `json:"employer"`
	// OpenJobs is how many open jobs of that kind (or employer and kind) there are.
	OpenJobs int `json:"open_jobs"`
	// Pay is the measured pay, or nil when it cannot be measured.
	Pay *PayStats `json:"pay"`
	// PayText describes how an employer posts pay when Pay is nil.
	PayText string `json:"pay_text"`
	// BestPaying lists the employers posting the most for the kind of job.
	BestPaying []EmployerPay `json:"best_paying"`
	// ByKind is an employer's pay by kind of job.
	ByKind []KindPay `json:"by_kind"`

	// Text is the server's plain-text summary.
	Text string `json:"text"`
}

PayResult is the answer of Pay. Its shape follows the PayParams, and only the fields of that shape are filled:

  • no parameters: AsOf, TypicalPayDefinition, Board, PayByKind, NoMarketRate
  • Kind: AsOf, Kind, OpenJobs, Pay, BestPaying
  • Employer: AsOf, Employer, Pay, PayText, ByKind
  • Kind and Employer: AsOf, Employer, Kind, OpenJobs, Pay

Pay is nil when too few of the employer's open jobs post an hourly rate to measure; PayText then says how that employer posts pay (for example weekly).

type PayStats

type PayStats struct {
	// Median is the median posted hourly rate.
	Median float64 `json:"median"`
	// TypicalLow is the 25th percentile of what jobs pay (the middle of each
	// advertised range).
	TypicalLow float64 `json:"typical_low"`
	// TypicalHigh is the 90th-percentile advertised ceiling.
	TypicalHigh float64 `json:"typical_high"`
	// RateSamples is how many distinct posted hourly rates went in.
	RateSamples int `json:"rate_samples"`
	// Employers is how many employers posted them.
	Employers int `json:"employers"`
	// OpenJobs is how many open jobs the measure covers.
	OpenJobs int `json:"open_jobs"`
	// NoRate is how many of those jobs post no hourly rate.
	NoRate int `json:"no_rate"`
	// MarketRate is true only where at least three employers post a rate.
	// It is false on the board-wide Board figures, which do not carry it.
	MarketRate bool `json:"market_rate"`
}

PayStats is posted hourly pay in US dollars, measured from the hourly rates open jobs state (before shift differentials and bonuses).

type RawResult

type RawResult struct {
	// Text is the server's plain-text summary.
	Text string
	// Data is the answer's structuredContent, undecoded.
	Data json.RawMessage
}

RawResult is the answer of Client.Call.

type SearchParams

type SearchParams struct {
	// Query is words every job must carry in its title, place, department or
	// schedule, for example "ICU", "night", "travel" or "Houston".
	Query string `json:"query,omitempty"`
	// Kind limits the search to one kind of job.
	Kind Kind `json:"kind,omitempty"`
	// Employer is an employer, AI-training program or job board: its slug
	// (for example "kaiser-permanente") or its name. Employers finds the slugs.
	Employer string `json:"employer,omitempty"`
	// State is a US state: its two-letter code ("TX") or its name ("Texas").
	State string `json:"state,omitempty"`
	// Remote limits the search to remote (work-from-home) jobs.
	Remote bool `json:"remote,omitempty"`
	// MinHourlyUSD keeps only jobs whose posted hourly ceiling reaches this many
	// US dollars (1 to 1000).
	MinHourlyUSD int `json:"min_hourly_usd,omitempty"`
	// Sort is the order of the results; the server's default is SortMixed.
	Sort Sort `json:"sort,omitempty"`
	// Limit is how many jobs to return (1 to 25, server default 10).
	Limit int `json:"limit,omitempty"`
}

SearchParams filters SearchJobs. Every field is optional; the zero value of a field leaves that filter off.

type SearchPay

type SearchPay struct {
	TypicalLow  float64 `json:"typical_low"`
	TypicalHigh float64 `json:"typical_high"`
	Median      float64 `json:"median"`
	// RateSamples is how many distinct posted hourly rates went in.
	RateSamples int `json:"rate_samples"`
	// Priced is how many matching jobs post an hourly rate.
	Priced int `json:"priced"`
	// Open is how many jobs match.
	Open int `json:"open"`
}

SearchPay is the posted pay across the jobs a search matches.

type SearchResult

type SearchResult struct {
	// Total is how many open jobs match the filters (all of them, not only the
	// ones returned in Jobs).
	Total int `json:"total"`
	// Pay is the posted pay across all matching jobs. Nil when none post a rate.
	Pay *SearchPay `json:"pay"`
	// Jobs are the jobs returned, at most the Limit.
	Jobs []Job `json:"jobs"`
	// More is the same search on the CareJobs.Now site.
	More string `json:"more"`
	// Text is the server's plain-text summary.
	Text string `json:"text"`
}

SearchResult is the answer of SearchJobs.

type Sort

type Sort string

Sort is the order of SearchJobs results.

const (
	SortMixed      Sort = "mixed"       // the board's order, employers interleaved
	SortNewest     Sort = "newest"      // most recently listed first
	SortHighestPay Sort = "highest_pay" // highest posted pay first
)

Sort orders. The server's default is SortMixed.

type StateJob

type StateJob struct {
	Title    string `json:"title"`
	Employer string `json:"employer"`
	// Where is the place of the job, for example "Dallas, TX".
	Where string `json:"where"`
	// Pay is the posted pay as text, empty when the posting states none.
	Pay    string `json:"pay"`
	Listed string `json:"listed"`
	URL    string `json:"url"`
}

StateJob is one of a state's newest jobs.

type StateParams

type StateParams struct {
	// State is a US state: two-letter code or name.
	State string `json:"state,omitempty"`
	// Kind is one kind of job; it needs a State.
	Kind Kind `json:"kind,omitempty"`
	// Limit is how many of the newest jobs to return for a state (1 to 25,
	// server default 10).
	Limit int `json:"limit,omitempty"`
}

StateParams selects what JobsByState returns. With no State it covers every US state; with a State, that state; with a State and a Kind, that kind of job in that state. A Kind without a State is an error the server reports.

type StatePay

type StatePay struct {
	// Kind is set in a state's by-kind list and empty in a state-and-kind answer.
	Kind Kind `json:"kind"`
	// P25 is the 25th percentile of the posted hourly rates.
	P25 float64 `json:"p25"`
	// Median is the median posted hourly rate.
	Median float64 `json:"median"`
	// P75 is the 75th percentile.
	P75 float64 `json:"p75"`
	// JobsWithRate is how many jobs post an hourly rate.
	JobsWithRate int `json:"jobs_with_rate"`
	// Employers is how many employers posted them (state answer only).
	Employers int `json:"employers"`
}

StatePay is the hourly pay quartiles of one kind of job in a state.

type StateResult

type StateResult struct {
	// States is every US state with its open jobs (no State given).
	States []StateSummary `json:"states"`

	// State is the two-letter state code.
	State string `json:"state"`
	// Name is the state's name.
	Name string `json:"name"`
	// Kind is the kind of job, in a state-and-kind answer.
	Kind Kind `json:"kind"`
	// OpenJobs is the open jobs in the state (or of the kind in the state).
	OpenJobs int `json:"open_jobs"`
	// Employers is how many employers have open jobs there.
	Employers int `json:"employers"`
	// URL is the page of the answer on CareJobs.Now.
	URL string `json:"url"`
	// ByKind is the state's open jobs by kind of job.
	ByKind []KindCount `json:"by_kind"`
	// PayByKind is the hourly pay quartiles by kind of job in the state.
	PayByKind []StatePay `json:"pay_by_kind"`
	// Pay is the hourly pay quartiles of the kind in the state. Nil when no job
	// posts a rate or the slice is too small.
	Pay *StatePay `json:"pay"`
	// Towns are the towns with the most jobs.
	Towns []Town `json:"towns"`
	// Hiring are the employers with the most jobs.
	Hiring []Hirer `json:"hiring"`
	// Newest are the newest jobs, at most the Limit.
	Newest []StateJob `json:"newest"`

	// Text is the server's plain-text summary.
	Text string `json:"text"`
}

StateResult is the answer of JobsByState. Its shape follows the StateParams, and only the fields of that shape are filled:

  • no State: States
  • a State: State, Name, OpenJobs, Employers, URL, ByKind, PayByKind, Towns, Hiring, Newest
  • a State and a Kind: State, Kind, OpenJobs, URL, and when the slice is big enough for a page of its own also Employers, Pay, Towns, Hiring, Newest

type StateSummary

type StateSummary struct {
	Code      string      `json:"code"`
	Name      string      `json:"name"`
	OpenJobs  int         `json:"open_jobs"`
	Employers int         `json:"employers"`
	TopKinds  []KindCount `json:"top_kinds"`
	URL       string      `json:"url"`
}

StateSummary is one state in the every-state answer.

type Tool

type Tool struct {
	Name        string `json:"name"`
	Title       string `json:"title"`
	Description string `json:"description"`
	// InputSchema is the tool's JSON Schema for its arguments, undecoded.
	InputSchema json.RawMessage `json:"inputSchema"`
	// Annotations are the MCP behaviour hints of the tool.
	Annotations ToolAnnotations `json:"annotations"`
}

Tool describes one tool as the server's tools/list answer does.

type ToolAnnotations

type ToolAnnotations struct {
	ReadOnlyHint    bool `json:"readOnlyHint"`
	DestructiveHint bool `json:"destructiveHint"`
	IdempotentHint  bool `json:"idempotentHint"`
	OpenWorldHint   bool `json:"openWorldHint"`
}

ToolAnnotations are the MCP behaviour hints of a tool. Every CareJobs.Now tool is read-only and idempotent.

type Town

type Town struct {
	// Key is the town's name.
	Key  string `json:"key"`
	Jobs int    `json:"jobs"`
	// Slug is the town's slug on CareJobs.Now.
	Slug string `json:"slug"`
}

Town is a town with open jobs.

Directories

Path Synopsis
cmd
carejobs command
Command carejobs searches US healthcare jobs and the pay employers post from the command line.
Command carejobs searches US healthcare jobs and the pay employers post from the command line.
examples
search command
Command search prints the best-paid open nursing jobs in a state.
Command search prints the best-paid open nursing jobs in a state.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL