QudraQudra Docs
Get API key

JavaScript SDK

The official Qudra SDK for Node.js and modern bundlers. Fully typed, zero-dependency at runtime (uses globalThis.fetch), with optional Express middleware for webhook verification.

Install

npm install @qudra/sdk
# or
pnpm add @qudra/sdk
# or
yarn add @qudra/sdk

Requires Node 18+ (for global fetch).

Quick start

import { QudraClient } from '@qudra/sdk';
 
const qudra = new QudraClient({
  apiKey: process.env.QUDRA_API_KEY!,
  sandbox: false, // set true to hit https://sandbox.api.qudrah.io
});
 
const job = await qudra.jobs.create({
  title: 'Senior Backend Engineer',
  description: 'Build the Qudra matching pipeline.',
  city: 'Riyadh',
  employment_type: 'full_time',
  salary_min: 18000,
  salary_max: 30000,
  currency: 'SAR',
});
 
console.log(job.qudra_url);

Configuration

new QudraClient({
  apiKey:    'qk_live_…',          // required
  sandbox:   false,                // optional — overrides baseUrl
  baseUrl:   'https://api.qudrah.io/v1', // optional — overrides both
  timeoutMs: 30_000,               // optional — default 30s
});

Jobs

// Create
const job = await qudra.jobs.create({ title: '…', city: 'Riyadh', employment_type: 'full_time', salary_min: 15000, salary_max: 22000 });
 
// List (auto-pagination helper)
for await (const job of qudra.jobs.list({ status: 'active' })) {
  console.log(job.id, job.title);
}
 
// Retrieve / Update / Delete
const j  = await qudra.jobs.retrieve('job_01HXY…');
const u  = await qudra.jobs.update('job_01HXY…', { status: 'paused' });
await qudra.jobs.delete('job_01HXY…');
 
// Bulk
const res = await qudra.jobs.bulkCreate({
  jobs: [
    { title: 'Backend',  city: 'Riyadh', employment_type: 'full_time', salary_min: 15000, salary_max: 22000 },
    { title: 'Frontend', city: 'Jeddah', employment_type: 'full_time', salary_min: 14000, salary_max: 20000 },
  ],
});
console.log(res.created.length, 'jobs created');

Webhooks

// Register
const wh = await qudra.webhooks.register({
  url:    'https://your-app.example.com/webhooks/qudra',
  events: ['job.created', 'job.matched'],
});
console.log('Save this secret:', wh.secret);
 
// Verify in a handler
import express from 'express';
const app = express();
 
app.post(
  '/webhooks/qudra',
  express.raw({ type: 'application/json' }),
  qudra.webhooks.expressMiddleware(process.env.QUDRA_WEBHOOK_SECRET!),
  (req, res) => {
    // req.qudraEvent is typed: { id, type, data, created_at }
    console.log(req.qudraEvent.type, req.qudraEvent.data);
    res.status(200).end();
  },
);

Error handling

import { QudraClient, QudraError } from '@qudra/sdk';
 
try {
  await qudra.jobs.create({ title: '', city: 'Riyadh' });
} catch (e) {
  if (e instanceof QudraError) {
    console.log(e.code);        // 'partner.validation_error'
    console.log(e.message);     // English
    console.log(e.messageAr);   // Arabic
    console.log(e.fields);      // { title: 'must be a non-empty string' }
    console.log(e.requestId);   // 'req_01HXY…'
  }
}

Analytics

const stats = await qudra.analytics.summary({ from: '2026-05-01', to: '2026-05-21' });
// { jobs_posted: 142, impressions: 8910, matches: 412, top_cities: [...] }

TypeScript

All resources, requests, and responses are fully typed. Import types directly:

import type { Job, JobCreate, WebhookEvent } from '@qudra/sdk';