Logo StartupKit
EN

Public Jobs API

Build your own job site (e.g. with Next.js on Vercel) on top of your Kit hiring pipeline. List published roles and receive applications through a public REST API and TypeScript SDK.

Why It Matters

Kit’s hosted career portal and embeddable widget cover most needs. But if you want full control over design — a bespoke careers site, a custom landing page per role, or a job board that matches your product — the Public Jobs API lets you read your published jobs and submit applications straight into your Kit pipeline, while Kit keeps owning screening, stages, interviews, and candidate communication.

There is also an official one-click Next.js template and a TypeScript SDK so you can ship a custom job site in minutes.

API Keys

Create a key pair under Hiring → Career Portal → Public API Keys. Each pair has:

  • Publishable key (pk_…) — safe to ship in a browser. It can read published jobs and submit applications, nothing else. It never exposes candidate data. You can restrict it to specific origins and protect it with your own Cloudflare Turnstile widget.
  • Secret key (sk_…) — for server-side use only (e.g. a Next.js Server Action). It skips the browser origin/Turnstile checks. Never expose it in client-side code. Neither key can read candidate PII.

The secret key is shown only once, when created or rotated. Rotate it any time from the key’s settings page; the previous secret stops working immediately.

Authenticate every request with a bearer header:

Authorization: Bearer sk_your_secret_key

Endpoints

Base URL: https://app.startupkit.app (or your career custom domain).

List published jobs

GET /api/public/v1/jobs?department=&location=&employment_type=&remote=&page=&per_page=

Returns only published roles for your account.

{
  "data": [
    {
      "id": "JdK2hQ8…",
      "title": "Senior Rails Developer",
      "department": "Engineering",
      "location": "Remote",
      "employment_type": "full_time",
      "remote": true,
      "published_at": "2026-06-01T12:00:00Z",
      "url": "https://careers.yourco.com/JdK2hQ8…",
      "salary": { "min": 120000, "max": 160000, "currency": "USD", "period": "YEAR" }
    }
  ],
  "pagination": { "current_page": 1, "total_pages": 3, "total_count": 42, "per_page": 20 }
}

The id is the job’s public token — use it for the detail and apply endpoints.

Get a job + its application form

GET /api/public/v1/jobs/:public_token

Returns the job plus an application_form describing exactly which fields and questions to render, the consent disclosure to show, accepted resume types/size, and whether Turnstile is required.

{
  "id": "JdK2hQ8…",
  "title": "Senior Rails Developer",
  "description_html": "<p>We're hiring…</p>",
  "accepting_applications": true,
  "stages": [{ "name": "Application Review", "type": "application_form" }],
  "application_form": {
    "fields": [
      { "name": "cover_letter", "type": "textarea", "label": "Cover letter", "required": false }
    ],
    "questions": [
      { "key": "why_us", "type": "text", "prompt": "Why do you want to join?", "required": true, "max_length": 2000 }
    ],
    "consent_disclosure_html": "<p>By applying you agree…</p>",
    "resume": {
      "content_types": ["application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
      "max_byte_size": 10485760
    },
    "turnstile": { "required": false, "sitekey": null }
  }
}

Upload a resume (presigned)

Resumes upload directly to storage, so they never pass through your server (avoiding serverless body-size limits).

POST /api/public/v1/direct_uploads
{ "blob": { "filename": "cv.pdf", "byte_size": 102400, "checksum": "<base64 MD5>", "content_type": "application/pdf" } }
{
  "signed_id": "eyJf…",
  "direct_upload": { "url": "https://…s3…", "headers": { "Content-Type": "application/pdf", "Content-MD5": "" } }
}

PUT the file bytes to direct_upload.url with the returned headers, then pass the signed_id as resume_signed_id when you submit the application.

Submit an application

POST /api/public/v1/jobs/:public_token/applications
{
  "application": {
    "email": "[email protected]",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "phone": "+1 555 0100",
    "responses": { "cover_letter": "…", "why_us": "…" },
    "resume_signed_id": "eyJf…"
  },
  "turnstile_token": "<token>"
}

Returns 201 with a minimal, PII-free confirmation:

{ "id": "app_9fQ…", "status": "submitted", "job": "JdK2hQ8…", "submitted_at": "2026-06-11T09:30:00Z" }

turnstile_token is only needed for browser (pk_) submissions when the key has Turnstile configured; server-side (sk_) calls skip it.

Errors

Errors return a consistent envelope:

{ "error": { "code": "validation_failed", "message": "Email can't be blank", "fields": { "email": ["can't be blank"] } } }
Status Code Meaning
401 invalid_key Missing or invalid API key
403 origin_not_allowed Browser origin not in the key’s allowlist
404 not_found Job not found or not published
409 already_applied This email already applied to this job
422 validation_failed Invalid application fields (see fields)
422 turnstile_failed Turnstile verification failed
422 invalid_content_type / file_too_large Rejected resume upload

Status Updates via Webhooks

To track applications after submission, configure outbound webhooks. Relevant events include application.submitted, application.advanced, and application.rejected, plus job_posting.published/paused/closed. Application payloads include both the numeric id and the API prefix_id (app_…), and the job’s public_token, so you can correlate webhook events with API records.

SDK & Next.js Template

  • TypeScript SDKnpm install @startupkit-app/jobs. A typed, zero-dependency client with listJobs, getJob, uploadFile, and apply.
  • Next.js template — a one-click Deploy to Vercel job board you can fork and customize. It wires up the secret key, dynamic application forms, presigned resume upload, and SEO/JSON-LD out of the box.

Both consume the contract above, so you can also build against any framework using plain HTTP.

Rate Limits

Application submissions are limited to 10/hour per IP and upload requests to 30/hour per IP, alongside the global API rate limits. Browser keys are additionally protected by their origin allowlist and optional Turnstile.

Type to search...