For developers
API and webhooks
Everything public on Vis is available as JSON: show your projects on your own website, build a job board, or make something we haven't thought of.
Get started
The base URL is https://visplatform.no/api/v1. No key is needed to read. Responses have CORS enabled, so you can call the API straight from the browser.
curl https://visplatform.no/api/v1/profiles/your-username
Show your latest projects on your own website:
const res = await fetch("https://visplatform.no/api/v1/profiles/your-username/projects");
const { data } = await res.json();
for (const project of data.slice(0, 3)) {
console.log(project.title, project.url, project.coverImage);
}Endpoints
GET /profiles/{username}Profile, CV and published projects
GET /profiles/{username}/projectsJust the projects
GET /projects?q=&tag=&featured=true&limit=24Search projects (newest first without q)
GET /projects/{id}One project with description (markdown), images and links
GET /jobs?q=&type=&remote=&limit=24Open jobs
GET /jobs/{id}One job
GET /companies/{slug}A company with its open jobs
Lists are in data. Errors look like { "error": { "status": 404, "message": "…" } }. Drafts, hidden and removed projects are not in the API, and email addresses are never shown.
Limits and keys
Without a key: 120 requests per minute per IP address. With a key: 1,200 per minute. Create one under Account → Developers and send it like this:
curl -H "Authorization: Bearer vis_…" https://visplatform.no/api/v1/jobs
Every response has X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Over the limit you get 429 with Retry-After.
Webhooks for companies
With the Business plan you can be notified when something happens to your jobs, e.g. to connect Vis to your applicant tracking system. Add a URL under Manage → Webhooks.
job.published– A job was publishedjob.closed– A job was closedjob.application_click– Someone clicked “Apply for this job”
Every delivery is a POST with JSON:
{
"id": "evt_…",
"type": "job.published",
"created": "2026-10-04T08:00:00.000Z",
"data": { "job": { "id": "…", "title": "Frontend developer", "status": "published", "url": "https://visplatform.no/stillinger/…" } }
}Check that it comes from us with Vis-Signature (t=time,v1=HMAC-SHA256 of “time.body” with the secret you were given):
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(body, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = createHmac("sha256", secret).update(`${t}.${body}`).digest("hex");
return timingSafeEqual(Buffer.from(v1, "hex"), Buffer.from(expected, "hex"));
}Respond with 2xx within 10 seconds. On 5xx or a timeout we retry twice. Redirects are not followed.
Badge and embeds
Without code: use “Share” on your profile or a project for a GitHub README badge (/api/merke/username) or a card you can embed with an iframe (/bygg-inn/profil/username).