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 in openconsultant: schemaVersion, id, canonicalUrl, company.name, availability.status and updatedAt.
  • 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.

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 availability and updatedAt when a consultant’s situation changes.
  • Update updatedAt in 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.