OpenAssignment · Draft specification 0.1.0
Specification
How a company publishes its consulting assignments as JSON on its own domain, and how consultants, agencies and matching services find and read them at the source.
Draft specification, version 0.1.0. This is an experimental first version, published to be tried out and criticised. Details may change before 1.0. Changes are listed in the changelog.
Overview
OpenAssignment defines two kinds of JSON documents and where to put them.
- An entry file at a fixed address,
/openassignment.json, which names the publisher and lists its assignments. - One assignment document per assignment, each at a URL of its own.
Both are ordinary files served over HTTPS. There is no API to implement, no registration and no central database.
The company that needs the work publishes the assignment on its own website. Everyone else reads it from there and links back to it. The information stays at the source, and the market connects around it.
The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are used as described in RFC 2119.
Terms
- Assignment: a defined piece of work that a company wants to buy from a consultant or a consulting company. It is a business-to-business engagement, not an employment.
- Publisher: the organisation that publishes and maintains the assignment on its own domain. Normally the company that needs the work. The publisher is the source of the information.
- Client: the organisation where the work is done. Usually the same as the publisher, and then it is not stated separately.
- Facilitator: an agency or other intermediary that helps fill the assignment, for example by sourcing and qualifying consultants, managing procurement or handling the agreement. Optional. A facilitator is not the source of the information.
- Consumer: any service that reads assignments in order to index, present or match them, such as a consulting company’s sales tool, an agency’s platform, a search service or an AI agent.
- Source address: the permanent URL of the assignment’s JSON document on the publisher’s domain, stated in
canonicalUrl. - Entry file: the JSON document that lists a publisher’s assignments.
Machine readable definitions
- Assignment schema:
/schemas/v0.1/schema.json - Entry file schema:
/schemas/v0.1/manifest.schema.json
The schemas are written in JSON Schema, draft 2020-12. Where this text and a schema disagree, the schema is the mistake: please report it.
The entry file
A publisher MUST serve the entry file at the root of the domain it publishes for:
https://example.com/openassignment.json
{
"$schema": "https://openassignment.io/schemas/v0.1/manifest.schema.json",
"standard": "OpenAssignment",
"schemaVersion": "0.1.0",
"publisher": {
"name": "Example Industries",
"url": "https://openassignment.io/examples/"
},
"updatedAt": "2026-10-01T08:00:00Z",
"assignments": [
{
"id": "urn:uuid:c4a7e2b1-3f58-4d9a-a6c0-7e1b5f2d8a43",
"url": "https://openassignment.io/examples/assignment.json",
"status": "open",
"updatedAt": "2026-10-01T08:00:00Z",
"htmlUrl": "https://openassignment.io/examples/#assignment"
}
]
}| Field | Type | Status | Description |
|---|---|---|---|
$schema | string (uri) | Optional | URL of the schema this document follows. |
standard | "OpenAssignment" | Required | Name of the standard. |
schemaVersion | string | Required | Version of OpenAssignment the entry file follows, for example "0.1.0". |
publisher | object | Required | The organisation that publishes the assignments on this domain. |
publisher.name | string | Required | Name of the organisation. |
publisher.url | string (uri) | Optional | The organisation's website. |
updatedAt | string (date-time) | Required | When the entry file or any listed assignment last changed. |
assignments | array of object | Required | One entry per published assignment. An empty list is valid. |
assignments[].id | string | Required | The assignment's stable identifier, identical to id in the assignment. |
assignments[].url | string (uri) | Required | The assignment's source address, identical to canonicalUrl in the assignment. |
assignments[].status | "open" | "paused" | "filled" | "closed" | Required | Current status, identical to status in the assignment. Lets clients notice a closed assignment without fetching it. |
assignments[].updatedAt | string (date-time) | Required | When the assignment last changed. Lets clients skip assignments they already have. |
assignments[].htmlUrl | string (uri) | Optional | URL of the human readable page. |
Rules for the entry file:
- Every
urlMUST be absolute, use HTTPS and equalcanonicalUrlin the assignment it points to. - Every
idandstatusMUST equal the values in the assignment it points to. updatedAtMUST change whenever an assignment is added, changed or removed.- An assignment that is no longer open SHOULD stay in the list with its new status for at least 30 days, so that consumers learn that it has closed. After that it MAY be removed.
The assignment
| Field | Type | Status | Description |
|---|---|---|---|
$schema | string (uri) | Optional | URL of the schema this document follows. |
schemaVersion | string | Required | Version of OpenAssignment the document follows, for example "0.1.0". |
id | string | Required | Stable identifier of the assignment, unique within the publisher. Must never change or be reused, even if the title or the file name changes. A UUID URN is recommended. |
canonicalUrl | string (uri) | Required | The source address: the permanent URL of this JSON document on the publisher's own domain. Every service that presents the assignment links back to it. |
title | string | Required | Title of the assignment, normally the role that is needed. |
description | string | Required | What the work is: background, tasks and expected outcome. Plain text. Line breaks separate paragraphs. |
publisher | object | Required | The organisation that publishes and maintains the assignment on its own domain. Normally the company that needs the work. The publisher is the source of the information. |
publisher.name | string | Required | Name of the organisation. |
publisher.url | string (uri) | Optional | The organisation's website. |
client | object | Optional | The organisation where the work is done, when that is not the publisher. Leave out when the publisher is the client. |
client.name | string | Required in parent | Name of the organisation. |
client.url | string (uri) | Optional | The organisation's website. |
facilitator | object | Optional | An agency or other intermediary that helps fill the assignment, for example by sourcing, qualifying or contracting consultants. Optional. A facilitator is not the source of the information: the publisher is. |
facilitator.name | string | Required in parent | Name of the facilitating organisation. |
facilitator.url | string (uri) | Optional | The facilitator's website. |
facilitator.role | string | Optional | What the facilitator does for this assignment, in a sentence. |
requiredSkills | array of object | Optional | Skills a consultant must have. |
requiredSkills[].name | string | Required in parent | Name of the skill. |
requiredSkills[].level | string | Optional | Expected level, for example "Senior". |
requiredSkills[].keywords | array of string | Optional | Specific technologies, methods or tools within the skill. |
preferredSkills | array of object | Optional | Skills that count in a consultant's favour but are not mandatory. |
preferredSkills[].name | string | Required in parent | Name of the skill. |
preferredSkills[].level | string | Optional | Expected level, for example "Senior". |
preferredSkills[].keywords | array of string | Optional | Specific technologies, methods or tools within the skill. |
location | object | Optional | Where on-site work takes place. |
location.city | string | Optional | City or town. |
location.region | string | Optional | Region, county or state. |
location.countryCode | string | Optional | ISO 3166-1 alpha-2 country code, for example "SE". |
remote | "onsite" | "hybrid" | "remote" | Optional | Way of working. onsite: at the client. hybrid: a mix of on-site and remote. remote: fully remote. |
engagementType | "full-time" | "part-time" | "project" | Optional | Form of the assignment. full-time and part-time are engagements paid by time. project is a delivery with a defined scope. |
workload | object | Optional | How much work the assignment is. |
workload.percent | integer | Optional | Share of full time, in percent. |
workload.hoursPerWeek | number | Optional | Expected hours per week. |
workload.description | string | Optional | Free text for anything the numbers do not capture. |
startDate | string (date) | Optional | Expected first day of the assignment. |
endDate | string (date) | Optional | Expected last day, if known. |
status | "open" | "paused" | "filled" | "closed" | Required | open: accepting interest. paused: temporarily not accepting interest. filled: a consultant has been appointed. closed: withdrawn or ended without being filled. |
publishedAt | string (date-time) | Required | When the assignment was first published. |
updatedAt | string (date-time) | Required | When the assignment last changed, including changes of status. |
expiresAt | string (date-time) | Optional | After this moment the assignment must no longer be presented as open, whatever status says. |
applicationUrl | string (uri) | Optional | Where to register interest: a web page or a mailto: address, at the publisher or at the facilitator. |
htmlUrl | string (uri) | Optional | URL of the human readable page at the publisher showing the same assignment. |
Nine fields are required. An assignment with only those looks like this:
{
"schemaVersion": "0.1.0",
"id": "urn:uuid:9d3f6a70-52c1-4b8e-8f2a-0c6e4b1d7a95",
"canonicalUrl": "https://openassignment.io/examples/assignment.minimal.json",
"title": "Data Engineer",
"description": "Six months of work on a data platform migration.",
"publisher": {
"name": "Example Industries"
},
"status": "open",
"publishedAt": "2026-10-01T08:00:00Z",
"updatedAt": "2026-10-01T08:00:00Z"
}The source and the roles around it
An assignment has one original, and it lives with the company that published it. Everything else in this specification follows from that.
The publisher is the source. The publisher writes the assignment, serves it from its own domain and keeps it current. Only the publisher changes it.
The source address is permanent. canonicalUrl is the address of the original. It MUST be an HTTPS URL on a domain the publisher controls, MUST be the address the document is actually served from, and SHOULD NOT change during the lifetime of the assignment.
The client is usually the publisher. When the company that needs the work publishes the assignment itself, client is left out. When one organisation publishes for another, for example a parent company for a subsidiary, publisher names the one that publishes and client names the one where the work is done.
A facilitator helps, but is not the source. Many companies work with an agency that sources and qualifies consultants, manages procurement or handles the agreement. The publisher MAY name that agency in facilitator and MAY point applicationUrl to it. This does not move the original: the assignment is still published and maintained by the publisher, at the publisher’s address.
{
"publisher": { "name": "Example Industries", "url": "https://example.com/" },
"facilitator": {
"name": "Example Sourcing",
"url": "https://sourcing.example/",
"role": "Qualifies consultants and manages the agreement on behalf of Example Industries."
}
}
Consumers build on the source. Agencies, platforms and other services are free to index assignments, present them, match them against consultants and build services around them. They do so from the original, link back to it and follow its updates. The rules are in Reading assignments.
Identity
An assignment is identified by id, not by its URL and not by its title.
- The
idMUST be unique within the publisher and MUST NOT change during the lifetime of the assignment. - The
idMUST NOT be reused for another assignment. - A random UUID written as a URN, such as
urn:uuid:c4a7e2b1-3f58-4d9a-a6c0-7e1b5f2d8a43, is recommended.
When the same assignment is presented by several services, the source address and the id let everyone recognise it as one assignment with one original.
Status and expiry
An assignment that has closed must not go on being presented as open. This is the part of the standard that matters most.
| Status | Meaning |
|---|---|
open |
The publisher accepts expressions of interest. |
paused |
Temporarily not accepting interest. May open again. |
filled |
A consultant has been appointed. |
closed |
Withdrawn, or ended without being filled. |
Publishers:
- MUST change
statusas soon as an assignment is no longer open. - MUST change
updatedAt, in both the assignment and the entry file, whenever the status changes. - SHOULD set
expiresAt, so that an assignment closes by itself if nobody remembers to update it.
Consumers:
- MUST NOT present an assignment as open unless
statusisopen. - MUST NOT present an assignment as open after
expiresAthas passed. - MUST stop presenting an assignment as open if its file can no longer be fetched or it has disappeared from the entry file.
- SHOULD read the entry file again at least once a day for as long as they show any of its assignments.
Assignments are not jobs
OpenAssignment describes consulting engagements, not employment. That is why the format has fields a job advert lacks, and lacks fields a job advert has.
publisher,clientandfacilitatorare separate roles, because the company that needs the work, the place where it is done and the agency that helps fill it can be three different organisations.engagementTypeandworkloaddescribe a purchase of time or of a delivery. There is no salary, no benefits and no employment form.startDateandendDatedescribe a limited period.
A consumer MUST NOT present an assignment as an offer of employment.
Relation to existing standards
The format was designed after reviewing Schema.org JobPosting and the JSON Resume project’s job description schema. Both are built around employment and have no way to express the status of an assignment or to name a facilitator alongside the company that needs the work, so OpenAssignment defines its own schema. Field names and structures are kept close to them where the meaning is the same: location and the skill objects use the JSON Resume shapes, which is also what OpenConsultant uses.
Publishers who also want their page understood by search engines can derive JobPosting markup from an assignment:
| OpenAssignment | Schema.org JobPosting |
|---|---|
title |
title |
description |
description |
publisher |
hiringOrganization |
location |
jobLocation |
remote |
jobLocationType |
engagementType |
employmentType, with the value CONTRACTOR |
requiredSkills |
skills |
startDate |
jobStartDate |
publishedAt |
datePosted |
expiresAt |
validThrough |
id |
identifier |
Human readable pages
The same assignment SHOULD also exist as an ordinary web page. Link the two together:
- In the assignment, set
htmlUrlto the page. - On the page, point to the JSON with a link element:
<link rel="alternate" type="application/json" href="https://example.com/assignments/frontend-developer.json" />
The page and the JSON SHOULD be generated from the same source, so they cannot drift apart.
Serving the files
- Files MUST be served over HTTPS.
- Files MUST be retrievable with a plain
GETrequest, without authentication, cookies or JavaScript. - The
Content-TypeMUST beapplication/json. - Files SHOULD allow cross-origin reads by sending
Access-Control-Allow-Origin: *. - Files MUST be encoded as UTF-8.
Reading assignments
A consumer finds and reads a publisher’s assignments in three steps.
- Fetch
https://<domain>/openassignment.json. - Check that
standardisOpenAssignmentand that it understands theschemaVersion. - Fetch each
urlinassignments. UsestatusandupdatedAtto skip assignments that are closed or have not changed.
Consumers:
- MUST ignore fields they do not recognise.
- MUST follow the rules under Status and expiry.
- MUST keep
canonicalUrlwith every copy and, wherever they present the assignment, link back to the original: tohtmlUrlwhen there is one, otherwise tocanonicalUrl. - MUST name the publisher as the source, and MUST NOT present themselves or a facilitator as the origin of the assignment.
- MUST replace their copy when the original changes, and SHOULD NOT alter the content they present.
- SHOULD send people who want to respond to
applicationUrl. - SHOULD identify themselves with a descriptive
User-Agent.
Consumers MAY add their own services around an assignment, such as matching, qualification or advice, as long as it stays clear what comes from the publisher and what the consumer has added.
Discovery in this version relies only on the fixed address. Later versions may add other mechanisms, such as .well-known or HTML metadata, without removing this one.
Extending the format
Unknown fields are allowed everywhere. Publishers MAY add their own. To avoid clashes with future versions of the standard, custom fields SHOULD start with x-, for example x-securityClearance.
Versioning
- Versions follow Semantic Versioning. This is
0.1.0. schemaVersionstates which version a document follows.- Each published minor version of the schemas has a permanent URL, for example
/schemas/v0.1/schema.json. Published schema files are not changed in incompatible ways. - Additions that old consumers can safely ignore are made within a version line. Breaking changes get a new version and a new schema URL.
Privacy and responsibility
Everything published according to this standard is public. The publisher decides what to publish and is responsible for it. That is the point of publishing at the source: the company that owns the information stays in control of it.
Client and facilitator. If you publish for another organisation, name it as client only when it has agreed to that. Name a facilitator only when the agency has agreed to be named. Do not publish internal project names, budgets, rates, procurement details or anything covered by a confidentiality agreement.
Personal data. An assignment should not need any. Use a functional address or a web form in applicationUrl, not a named person’s private contact details. If you do publish personal data, such as a contact person’s name, the GDPR applies within the EU and EEA and you need a legal basis and must have informed the person.
What not to publish. Never put secrets, API keys or internal identifiers from business systems in an assignment. Do not describe security arrangements or systems in more detail than a public advert would.
Updating and unpublishing. Change status when an assignment closes and keep it listed for a while, as described above. To withdraw an assignment completely, remove it from the entry file and stop serving the file. A removed file SHOULD answer with HTTP 404 or 410.
Reuse. Consumers MAY index, present and redistribute assignments. They are responsible for keeping their copies current, MUST honour status changes and removals, and MUST link back to the original.