Developer guide / Vendors

Connect a candidate roster

Refer people in batches, let each trainer choose whether to share their status, and keep your recruiting system up to date when a shared tier changes.

Get vendor access

The owner of an active vendor organization with a signed agreement can create a vendor key. Sign in with your verified email and two-factor authentication, then choose vendor access in the developer console.

Store the key in your server’s secret manager. Send it in the Authorization: Bearer header to the production base URL https://app.silktrain.ai/api/vendor/v1. Use a vendor key for roster calls. Employer keys cover a separate hiring API.

Submit a candidate batch

POST /candidates/batch

Submit up to 100 candidates in a JSON array. Assign a stable external_id from your own roster. Supply the email address the trainer will verify when they sign in to SilkTrain.

curl --request POST \
  --url https://app.silktrain.ai/api/vendor/v1/candidates/batch \
  --header "Authorization: Bearer ${SILKTRAIN_VENDOR_KEY}" \
  --header 'Content-Type: application/json' \
  --header 'Accept: application/json' \
  --data '{"candidates":[{"external_id":"worker-001","email":"[email protected]"}]}'

A successful request returns HTTP 200 with an items array. Save the SilkTrain id alongside your external reference. For a pending referral, privately give the returned claim_url to the person you referred.

The trainer signs in using the matching verified email, sees the organization requesting access and decides whether to share. Sending a referral does not enroll the person in a job or reveal their clearance.

You can retry a batch using the same external references and emails. Reusing an existing reference with a different email rejects the batch with HTTP 409. Resolve the roster conflict before retrying.

Read a candidate’s current status

GET /candidates/{id}

Use the SilkTrain UUID returned by the batch endpoint. Your organization can read its own referrals. This example shows the response before a candidate shares access.

{
  "id": "a5330b99-75c2-483f-9655-6f8ade860b15",
  "external_id": "worker-001",
  "status": "awaiting_consent",
  "tier": null,
  "compliance": null
}
awaiting_consent
The candidate has not authorized sharing with your organization. Tier and compliance are null.
shared
The candidate authorized access. Compliance is eligible or not_cleared. The tier field can contain 2, 3 or null. Read both fields before displaying a clearance summary.
withdrawn
The candidate withdrew access. Tier and compliance are null. Remove previously displayed values from your recruiting dashboard.

Refresh status before relying on it for a placement. Shared eligibility concerns the marketplace. Projects with language, credential or safety requirements still need assignment-specific checks.

Receive signed tier-change events

Arrange an HTTPS receiver URL with the SilkTrain operator. Once the exact address is approved for your vendor organization, its owner can enable the receiver and get its signing secret in the developer console. Keep this secret separate from the API key.

When an authorized candidate’s shareable tier changes, SilkTrain posts a candidate.tier_changed notification. An event identifies the referral so your backend can read current status.

{
  "id": "028ef549-0479-4486-90ea-6391e9a4026d",
  "type": "candidate.tier_changed",
  "candidate_id": "a5330b99-75c2-483f-9655-6f8ade860b15",
  "occurred_at": "2026-11-01T09:30:00Z"
}
  1. Read the incoming body as raw bytes. Verify the timestamp and HMAC before decoding its JSON.
  2. Compare X-SilkTrain-Event with the event’s id. Record accepted IDs in durable storage so repeated deliveries trigger the work only once.
  3. Acknowledge with a 2xx response once the event is safely recorded or queued. Delivery is retried after temporary failures, and events can arrive out of order.
  4. Use candidate_id to fetch the latest status. Recheck sharing when you need it, including before displaying a saved result.
Verify the signature in Node.js

Pass a Node server’s incoming headers and the unmodified body buffer. Use the exact signing secret from the developer console.

import { createHmac, timingSafeEqual } from 'node:crypto';

function authentic(headers, rawBody, secret) {
  const ts = headers['x-silktrain-timestamp'];
  const sig = headers['x-silktrain-signature'];
  if (typeof ts !== 'string' || !/^\d+$/.test(ts)) return false;
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  if (typeof sig !== 'string' || !/^sha256=[a-f0-9]{64}$/.test(sig)) return false;
  const expected = createHmac('sha256', secret)
    .update(ts + '.').update(rawBody).digest();
  return timingSafeEqual(expected, Buffer.from(sig.slice(7), 'hex'));
}

Handle errors and retries

Authentication or access failure
Verify the vendor key, your organization’s access and the base URL. Keep credentials out of logs and client-side code.
409 · Conflicting roster reference
Check the email attached to the existing external reference. Preserve the original mapping until the conflict is resolved.
422 · Validation error
Check the JSON structure, candidate identifiers, email format and batch size before retrying.
429 · Too many requests
Each client address can send 12 batch requests and 90 API requests a minute. Reduce concurrency and retry after the delay in the Retry-After header. Use the same external references when resubmitting a batch.

Open the developer console · Return to services for data vendors