softon.dev hosts independent data APIs — jobs, events, quotes, and whatever we ship next — behind one account, one key and one response envelope. Read the docs for one of them and you can read the docs for all of them.
Every API on softon.dev ships the same auth, pagination, filtering, error shape and rate-limit headers. New services drop into this grid — and into the docs — without a new mental model for anyone.
Job Data API
Live
Postings from company career pages and boards, deduplicated per source, with the employment type, job function and career level the source itself publishes, plus the full description on a detail fetch.
GET /v1/jobs
GET /v1/jobs/{id}
POST /v1/jobs/liveness
GET /v1/companies/{id}/jobs
170K postingsRefreshed every 15h · last 3hv1 · stable
Concerts, theatre, exhibitions and cinema with geocoded venues, and — where the source publishes them — per-showing schedules and remaining ticket counts recorded at every scrape.
Attributed quotations with author, category and collection provenance, plus a quote-of-the-day endpoint that is deterministic for a date, so it can be cached.
GET /v1/quotes
GET /v1/quotes/{id}
GET /v1/quotes/random
521K quotationsOne-time import · last 35dv1 · stable
The central bank's official daily AZN bulletin — 38 currencies and 4 bank metals — with the date you asked for AND the date the bank published, so a weekend's repeated numbers are marked as repeats rather than stored as a fresh publication.
Which release each upstream genome data source is on — RefSeq, dbSNP, 1000 Genomes/IGSR and NCBI Datasets — read from each source itself rather than hardcoded, with how the latest probe went beside it. Release markers only: no sequence, assembly or variant data.
Whether a watched URL answered us, why not if it did not, and how long it has been that way — with the vantage the request left from on every row. Status codes only: no page content is stored or served.
Every response is { data, meta, error } with cursor pagination in meta.next and the same error codes. Write your client once; point it at any dataset. Rate limits and usage roll up to a single account.
Docs that grow themselves
Each service publishes a machine-readable schema at /v1/schema; the portal renders navigation, endpoint pages, field tables and snippets from it. Adding an API adds a docs section — nobody writes the boilerplate twice.
Server-rendered, so it's quick
The site and dashboard are Go templates with HTMX for the interactive parts: search, key management and live request testing return HTML fragments. No client bundle to ship, nothing to hydrate, works with JS off for the parts that matter.
Quickstart
Three minutes to the first row
Sign up, copy the key, call the endpoint. The same snippet works against every dataset in the catalog — swap the path and the filters. No SDK to install: these are the standard library in each language, and they run as they are.
req, _ := http.NewRequestWithContext(ctx, "GET",
"https://api.softon.dev/v1/jobs", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("SOFTON_KEY"))
q := req.URL.Query()
q.Set("q", "golang")
q.Set("remote", "true")
q.Set("updated_after", "2026-08-16T09:00:00Z")
req.URL.RawQuery = q.Encode()
res, err := http.DefaultClient.Do(req)
if err != nil { log.Fatal(err) }
defer res.Body.Close()
var page struct {
Data []Job `json:"data"`
Meta struct{ Next *string`json:"next"` } `json:"meta"`
}
if err := json.NewDecoder(res.Body).Decode(&page); err != nil { log.Fatal(err) }
// page.Meta.Next → send it back as ?cursor= for the following page
import json, os, urllib.parse, urllib.request
url = "https://api.softon.dev/v1/jobs" + "?" + urllib.parse.urlencode({
"q": "golang",
"remote": "true",
"updated_after": "2026-08-16T09:00:00Z",
})
req = urllib.request.Request(url, headers={
"Authorization": "Bearer " + os.environ["SOFTON_KEY"],
})
page = json.load(urllib.request.urlopen(req))
# page["meta"]["next"] → send it back as ?cursor= for the following page
const url = new URL("https://api.softon.dev/v1/jobs");
url.searchParams.set("q", "golang");
url.searchParams.set("remote", "true");
url.searchParams.set("updated_after", "2026-08-16T09:00:00Z");
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.SOFTON_KEY}` },
});
if (!res.ok) thrownew Error(`${res.status} ${await res.text()}`);
const { data, meta } = await res.json();
// meta.next → send it back as ?cursor= for the following page
Every account starts free — 1,000 requests a month, all
live datasets, no card. The plans above are for when you outgrow it: pick one and we
will contact you to settle payment card to card. Already have an account? Ask from
your dashboard.
Every response is { data, meta, error }. Learn one dataset and you have learned all of them — and where a source publishes nothing, you get null rather than a plausible guess.
The response envelope — specified once, identical on every dataset.Built on softon.dev