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
eligibleornot_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"
}
- Read the incoming body as raw bytes. Verify the timestamp and HMAC before decoding its JSON.
- Compare
X-SilkTrain-Eventwith the event’sid. Record accepted IDs in durable storage so repeated deliveries trigger the work only once. - 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.
- Use
candidate_idto 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-Afterheader. Use the same external references when resubmitting a batch.
Open the developer console · Return to services for data vendors