Components
@ojobs/sdk ships the data layer, but most integrators just want a job list on their page without building the UI from scratch. <JobsBoard /> is a copy-paste component — you own the code, so you can restyle it freely.
Install the SDK
npm install @ojobs/sdkServer Component (recommended)
If your app runs on the server (Next.js App Router, Remix, etc.), use the server version — your API key never reaches the browser.
import { JobsBoard } from "@/components/jobs-board";
export default function CareersPage() {
return (
<div className="mx-auto max-w-2xl py-12">
<h1 className="mb-6 text-2xl font-semibold">Open Positions</h1>
<JobsBoard apiKey={process.env.OJOBS_API_KEY!} />
</div>
);
}Copy the component source from jobs-board-server.tsx into your project.
Client Component (SPAs, no server runtime)
If you're client-only (Vite, CRA, a static SPA), your API key can't be embedded in the browser bundle — set up a tiny proxy route on your own backend first, then point the client component at it.
1. Add a proxy route on your backend (keeps the key server-side):
// your-backend/api/jobs.ts
import { OJobsClient } from "@ojobs/sdk";
const ojobs = new OJobsClient({ apiKey: process.env.OJOBS_API_KEY! });
export async function GET() {
const jobs = await ojobs.jobs.list();
return Response.json({ jobs });
}2. Point the client component at it:
import { JobsBoardClient } from "@/components/jobs-board-client";
export default function CareersPage() {
return <JobsBoardClient endpoint="/api/jobs" />;
}What it handles for you
- Badge colors and labels for
REMOTE/ONSITE/HYBRID/INTERNSHIP - Naira-formatted rate display
- Loading skeletons and an error state (client version)
- An empty state when there are no open jobs
Try it safely with a test key
Use a ojobs_test_... key while you style the component — it always returns the same sandbox jobs, so you can iterate on layout without needing an approved organisation account yet, and without any real data on screen. See Authentication.