OpenConsultant · Draft specification 0.1.0
Get started
For consulting companies. Publish your first consultant profile on your own website in five steps.
Before you start
You publish the profiles yourself, on your own domain. That makes your website the source: clients, agencies and matching services read the profiles from you and link back to you.
Decide which consultants to publish and make sure each of them knows what will be public. A published profile can be read and presented by anyone. See Privacy and responsibility in the specification.
1. Write a profile
Create one JSON file per consultant. Start from the smallest valid profile and add what you have.
{
"$schema": "https://openconsultant.io/schemas/v0.1/schema.json",
"basics": {
"name": "Anna Andersson",
"label": "Senior Frontend Developer",
"summary": "Frontend developer focused on accessible web applications."
},
"skills": [
{ "name": "Frontend development", "keywords": ["TypeScript", "Vue"] }
],
"openconsultant": {
"schemaVersion": "0.1.0",
"id": "urn:uuid:6f1d2c3a-8b4e-4f7a-9c21-5d0e7a3b9f10",
"canonicalUrl": "https://example.com/consultants/anna-andersson.json",
"company": { "name": "Example Consulting", "url": "https://example.com/" },
"availability": { "status": "available-from", "availableFrom": "2027-02-01" },
"remote": "hybrid",
"engagementTypes": ["full-time"],
"updatedAt": "2026-10-01T08:00:00Z"
}
}
What is required and what is optional:
- Required:
basics.name, and inopenconsultant:schemaVersion,id,canonicalUrl,company.name,availability.statusandupdatedAt. - Optional: everything else. The more you fill in, the easier the consultant is to find.
company is your consulting 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 profile an id that never changes. Generate a UUID once and keep it:
node -e "console.log('urn:uuid:' + crypto.randomUUID())"
If your profiles 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 profiles in a file called openconsultant.json.
{
"standard": "OpenConsultant",
"schemaVersion": "0.1.0",
"publisher": { "name": "Example Consulting", "url": "https://example.com/" },
"updatedAt": "2026-10-01T08:00:00Z",
"consultants": [
{
"id": "urn:uuid:6f1d2c3a-8b4e-4f7a-9c21-5d0e7a3b9f10",
"url": "https://example.com/consultants/anna-andersson.json",
"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://openconsultant.io/schemas/v0.1/schema.json
curl -sO https://openconsultant.io/schemas/v0.1/manifest.schema.json
npx ajv-cli@5 validate --spec=draft2020 -c ajv-formats -s schema.json -d consultants/anna-andersson.json
npx ajv-cli@5 validate --spec=draft2020 -c ajv-formats -s manifest.schema.json -d openconsultant.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 profile is never published.
4. Publish
Put the files on your website so that they answer at these addresses:
https://example.com/openconsultant.json
https://example.com/consultants/anna-andersson.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:
/openconsultant.json
Access-Control-Allow-Origin: *
/consultants/*
Access-Control-Allow-Origin: *
On nginx:
location = /openconsultant.json { add_header Access-Control-Allow-Origin "*"; }
location /consultants/ { add_header Access-Control-Allow-Origin "*"; }
Check the result:
curl -sI https://example.com/openconsultant.json
Look for content-type: application/json and access-control-allow-origin: * in the answer.
5. Link the page and the data
If the consultant also has an ordinary profile page, connect the two. In the JSON, set openconsultant.htmlUrl to the page. On the page, add:
<link rel="alternate" type="application/json" href="https://example.com/consultants/anna-andersson.json" />
Keeping it current
- Update
availabilityandupdatedAtwhen a consultant’s situation changes. - Update
updatedAtin the entry file whenever any profile changes. - When a consultant leaves, remove the profile from the entry file and delete the file.
Reading profiles from the source
Clients, agencies and matching services read profiles directly from the consulting companies that publish them. It takes a few lines of code: fetch the entry file, then each profile it lists.
async function readConsultants(domain) {
const manifest = await fetch(`https://${domain}/openconsultant.json`).then((r) => r.json());
if (manifest.standard !== 'OpenConsultant') throw new Error('Not an OpenConsultant entry file');
return Promise.all(manifest.consultants.map((entry) => fetch(entry.url).then((r) => r.json())));
}
const profiles = await readConsultants('example.com');
const available = profiles.filter((p) => p.openconsultant.availability.status === 'available');
Ignore fields you do not recognise, keep the id as your key and read the entry file again regularly. Wherever you present a profile, name the publishing company and link back to the original at htmlUrl or canonicalUrl. The full rules are in Reading profiles.