OpenAssignment · Draft specification 0.1.0
Get started
For companies that need consulting expertise. Publish your first assignment on your own website in five steps.
Before you start
You publish the assignment yourself, on your own domain. That makes your website the source: consultants, agencies and matching services read the assignment from you and link back to you.
Decide what may be public. A published assignment can be read and presented by anyone, so leave out rates, budgets and details that are not meant for the open market. See Privacy and responsibility in the specification.
1. Describe the assignment
Create one JSON file per assignment.
{
"$schema": "https://openassignment.io/schemas/v0.1/schema.json",
"schemaVersion": "0.1.0",
"id": "urn:uuid:c4a7e2b1-3f58-4d9a-a6c0-7e1b5f2d8a43",
"canonicalUrl": "https://example.com/assignments/frontend-developer.json",
"title": "Senior Frontend Developer",
"description": "Lead the component work in our design system rollout together with our in-house team of four.",
"publisher": { "name": "Example Industries", "url": "https://example.com/" },
"requiredSkills": [
{ "name": "Frontend development", "level": "Senior", "keywords": ["TypeScript", "Vue"] }
],
"location": { "city": "Stockholm", "countryCode": "SE" },
"remote": "hybrid",
"engagementType": "full-time",
"workload": { "percent": 100 },
"startDate": "2027-02-01",
"status": "open",
"publishedAt": "2026-10-01T08:00:00Z",
"updatedAt": "2026-10-01T08:00:00Z",
"expiresAt": "2027-01-15T23:59:59Z",
"applicationUrl": "https://example.com/assignments/frontend-developer/apply"
}
What is required and what is optional:
- Required:
schemaVersion,id,canonicalUrl,title,description,publisher.name,status,publishedAtandupdatedAt. - Optional: everything else. Skills, location, workload and start date are what readers filter on, so include them when you can.
publisher is your company. canonicalUrl is the address where this file will be served from your website. It is the source address that everyone else links back to, so choose one you can keep.
Give every assignment an id that never changes. Generate a UUID once and keep it:
node -e "console.log('urn:uuid:' + crypto.randomUUID())"
If your assignments already exist in a CMS or a business system, generate the JSON from there instead of writing it by hand. The aim is that nobody has to update the same information in two places.
2. Write the entry file
List your assignments in a file called openassignment.json. Each entry repeats the assignment’s status, so that readers notice a closed assignment without fetching it.
{
"standard": "OpenAssignment",
"schemaVersion": "0.1.0",
"publisher": { "name": "Example Industries", "url": "https://example.com/" },
"updatedAt": "2026-10-01T08:00:00Z",
"assignments": [
{
"id": "urn:uuid:c4a7e2b1-3f58-4d9a-a6c0-7e1b5f2d8a43",
"url": "https://example.com/assignments/frontend-developer.json",
"status": "open",
"updatedAt": "2026-10-01T08:00:00Z"
}
]
}
3. Validate
Check your files against the published schemas before you publish. Download the schemas, then validate with any JSON Schema validator. With Node.js installed:
curl -sO https://openassignment.io/schemas/v0.1/schema.json
curl -sO https://openassignment.io/schemas/v0.1/manifest.schema.json
npx ajv-cli@5 validate --spec=draft2020 -c ajv-formats -s schema.json -d assignments/frontend-developer.json
npx ajv-cli@5 validate --spec=draft2020 -c ajv-formats -s manifest.schema.json -d openassignment.json
A valid file is reported as valid. An invalid one is listed with the path of each field that is wrong.
Any JSON Schema validator that supports draft 2020-12 works. Run the validation in your build or CI so that an invalid assignment is never published.
4. Publish
Put the files on your website so that they answer at these addresses:
https://example.com/openassignment.json
https://example.com/assignments/frontend-developer.json
The files must be served over HTTPS as application/json, without login, and should allow cross-origin reads. Most hosts set the content type by themselves. The cross-origin header usually has to be added.
On Netlify, in a _headers file:
/openassignment.json
Access-Control-Allow-Origin: *
/assignments/*
Access-Control-Allow-Origin: *
On nginx:
location = /openassignment.json { add_header Access-Control-Allow-Origin "*"; }
location /assignments/ { add_header Access-Control-Allow-Origin "*"; }
Check the result:
curl -sI https://example.com/openassignment.json
Look for content-type: application/json and access-control-allow-origin: * in the answer.
5. Link the page and the data
If the assignment also has an ordinary web page, connect the two. In the JSON, set htmlUrl to the page. On the page, add:
<link rel="alternate" type="application/json" href="https://example.com/assignments/frontend-developer.json" />
Working with an agency
Publishing at the source does not mean doing everything yourself. If an agency sources and qualifies consultants, manages procurement or handles the agreement for you, name it in the assignment and send interest its way:
{
"facilitator": {
"name": "Example Sourcing",
"url": "https://sourcing.example/",
"role": "Qualifies consultants and manages the agreement on behalf of Example Industries."
},
"applicationUrl": "https://sourcing.example/apply/frontend-developer"
}
The assignment is still yours, published on your domain and updated by you. The agency, and every other service, works from that one original.
When the assignment closes
This is the step that keeps the market clean.
- Change
statustofilledorclosed, in the assignment and in the entry file. - Update
updatedAtin both. - Leave the assignment listed for about 30 days so that every service that presents it learns that it has closed. Then remove it.
Set expiresAt when you publish. If you forget to close the assignment, it closes by itself.
Reading assignments from the source
Consultants, agencies and matching services read assignments directly from the companies that publish them. It takes a few lines of code: fetch the entry file, then each open assignment it lists.
async function readOpenAssignments(domain) {
const manifest = await fetch(`https://${domain}/openassignment.json`).then((r) => r.json());
if (manifest.standard !== 'OpenAssignment') throw new Error('Not an OpenAssignment entry file');
const open = manifest.assignments.filter((entry) => entry.status === 'open');
const assignments = await Promise.all(open.map((entry) => fetch(entry.url).then((r) => r.json())));
const now = new Date();
return assignments.filter((a) => a.status === 'open' && !(a.expiresAt && new Date(a.expiresAt) < now));
}
const assignments = await readOpenAssignments('example.com');
Ignore fields you do not recognise, keep the id as your key and read the entry file again at least daily. Wherever you present an assignment, name the publisher and link back to the original at htmlUrl or canonicalUrl. The full rules are in Reading assignments.