OpenConsultant · Draft specification 0.1.0

Specification

How a consulting company publishes its consultant profiles as JSON on its own domain, and how clients, 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

OpenConsultant defines two kinds of JSON documents and where to put them.

  • An entry file at a fixed address, /openconsultant.json, which names the publisher and lists its profiles.
  • One profile per consultant, 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 consulting company that offers the consultant publishes the profile 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

  • Publisher: the consulting company that offers the consultant and publishes the profile on its own domain. The publisher is the source of the information.
  • Consumer: any service that reads profiles in order to index, present or match them, such as a client’s supplier system, an agency’s platform, a search service or an AI agent.
  • Profile: the JSON document describing one consultant.
  • Source address: the permanent URL of the profile’s JSON document on the publisher’s domain, stated in openconsultant.canonicalUrl.
  • Entry file: the JSON document that lists a publisher’s profiles.

Machine readable definitions

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/openconsultant.json
/examples/manifest.jsonDownload /examples/manifest.json
{
  "$schema": "https://openconsultant.io/schemas/v0.1/manifest.schema.json",
  "standard": "OpenConsultant",
  "schemaVersion": "0.1.0",
  "publisher": {
    "name": "Example Consulting",
    "url": "https://openconsultant.io/examples/"
  },
  "updatedAt": "2026-10-01T08:00:00Z",
  "consultants": [
    {
      "id": "urn:uuid:6f1d2c3a-8b4e-4f7a-9c21-5d0e7a3b9f10",
      "url": "https://openconsultant.io/examples/profile.json",
      "updatedAt": "2026-10-01T08:00:00Z",
      "htmlUrl": "https://openconsultant.io/examples/#profile"
    }
  ]
}
Fields of the entry file
FieldTypeStatusDescription
$schemastring (uri)OptionalURL of the schema this document follows.
standard"OpenConsultant"RequiredName of the standard.
schemaVersionstringRequiredVersion of OpenConsultant the entry file follows, for example "0.1.0".
publisherobjectRequiredThe consulting company that publishes the profiles on this domain.
publisher.namestringRequiredName of the organisation.
publisher.urlstring (uri)OptionalThe organisation's website.
updatedAtstring (date-time)RequiredWhen the entry file or any listed profile last changed.
consultantsarray of objectRequiredOne entry per published profile. An empty list is valid.
consultants[].idstringRequiredThe profile's stable identifier, identical to openconsultant.id in the profile.
consultants[].urlstring (uri)RequiredThe profile's source address, identical to openconsultant.canonicalUrl in the profile.
consultants[].updatedAtstring (date-time)OptionalWhen the profile last changed. Lets clients skip profiles they already have.
consultants[].htmlUrlstring (uri)OptionalURL of the human readable profile page.

Rules for the entry file:

  • Every url MUST be absolute, use HTTPS and equal openconsultant.canonicalUrl in the profile it points to.
  • Every id MUST equal openconsultant.id in the profile it points to.
  • updatedAt MUST change whenever a profile is added, changed or removed.
  • A profile that is no longer offered MUST be removed from the list.

The profile

A profile is a JSON Resume document with one extra top-level object, openconsultant. JSON Resume allows additional properties, so a profile remains a valid JSON Resume document and works with existing JSON Resume tools.

Resume content

OpenConsultant reuses the JSON Resume sections without changing them. The ones that matter most for consulting are listed below. Any other JSON Resume section MAY be included.

Section Contains
basics Name, role, profile text and contact information
work Professional experience
skills Competences, each with name, optional level and keywords
education Education
certificates Certifications
projects Reference projects
languages Spoken languages

Only basics.name is required from the resume content.

Fields of basics
FieldTypeStatusDescription
basics.namestringRequiredThe consultant's name as it should be presented.
basics.labelstringOptionalProfessional role or title, for example "Senior Frontend Developer".
basics.summarystringOptionalShort profile text.
basics.imagestringOptionalURL of a portrait. Publish only with the person's knowledge.
basics.emailstring (email)OptionalContact address. Never required. Prefer openconsultant.contact for contact through the company.
basics.phonestringOptionalPhone number. Never required.
basics.urlstring (uri)OptionalA personal or professional web page.
basics.locationobjectOptionalWhere the consultant is based, in JSON Resume form (city, region, countryCode).

The openconsultant object

Everything specific to consulting lives in the openconsultant object: who offers the consultant, when they are available, where and how they work.

Fields of the openconsultant object
FieldTypeStatusDescription
openconsultant.schemaVersionstringRequiredVersion of OpenConsultant the profile follows, for example "0.1.0".
openconsultant.idstringRequiredStable identifier of the profile, unique within the publisher. Must never change, even if the consultant's name or the file name does. A UUID URN is recommended.
openconsultant.canonicalUrlstring (uri)RequiredThe source address: the permanent URL of this JSON document on the company's own domain. Every service that presents the profile links back to it.
openconsultant.companyobjectRequiredThe consulting company that offers the consultant and publishes the profile. The company is the source of the information.
openconsultant.company.namestringRequiredName of the organisation.
openconsultant.company.urlstring (uri)OptionalThe organisation's website.
openconsultant.availabilityobjectRequiredWhether the consultant can take on new work.
openconsultant.availability.status"available" | "available-from" | "busy" | "unknown"Requiredavailable: free now. available-from: free from the date in availableFrom. busy: not available. unknown: the publisher does not state availability.
openconsultant.availability.availableFromstring (date)OptionalFirst day the consultant is available. Required when status is available-from.
openconsultant.locationsarray of objectOptionalGeographic areas where the consultant can work on site.
openconsultant.locations[].citystringOptionalCity or town.
openconsultant.locations[].regionstringOptionalRegion, county or state.
openconsultant.locations[].countryCodestringOptionalISO 3166-1 alpha-2 country code, for example "SE".
openconsultant.remote"onsite" | "hybrid" | "remote"OptionalPreferred way of working. onsite: at the client. hybrid: a mix of on-site and remote. remote: fully remote.
openconsultant.engagementTypesarray of "full-time" | "part-time" | "project"OptionalForms of engagement the consultant is offered for.
openconsultant.contactobjectOptionalHow to enquire about the consultant, normally through the company rather than the individual.
openconsultant.contact.namestringOptionalPerson or function to contact.
openconsultant.contact.emailstring (email)OptionalContact address at the company.
openconsultant.contact.urlstring (uri)OptionalContact page or enquiry form.
openconsultant.updatedAtstring (date-time)RequiredWhen the profile was last changed, including changes to availability.
openconsultant.htmlUrlstring (uri)OptionalURL of the human readable profile page at the company showing the same information.

A profile with only the required fields looks like this:

/examples/profile.minimal.jsonDownload /examples/profile.minimal.json
{
  "basics": {
    "name": "Erik Example"
  },
  "openconsultant": {
    "schemaVersion": "0.1.0",
    "id": "urn:uuid:2b9c1e54-7a3d-4c8f-b6e0-91f4d2a7c355",
    "canonicalUrl": "https://openconsultant.io/examples/profile.minimal.json",
    "company": {
      "name": "Example Consulting"
    },
    "availability": {
      "status": "unknown"
    },
    "updatedAt": "2026-10-01T08:00:00Z"
  }
}

The source

A profile has one original, and it lives with the consulting company that published it. Everything else in this specification follows from that.

The publisher is the source. The consulting company writes the profile, serves it from its own domain and keeps it current. Only the publisher changes it. openconsultant.company names the publisher.

The source address is permanent. openconsultant.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 profile.

Consumers build on the source. Clients, agencies, platforms and other services are free to index profiles, present them, match them against assignments and build services around them. They do so from the original, link back to it and follow its updates, so that nobody has to maintain a separate version of a consultant’s CV. The rules are in Reading profiles.

Identity

A profile is identified by openconsultant.id, not by its URL and not by the consultant’s name.

  • The id MUST be unique within the publisher and MUST NOT change during the lifetime of the profile.
  • The id MUST NOT be reused for another person.
  • A random UUID written as a URN, such as urn:uuid:6f1d2c3a-8b4e-4f7a-9c21-5d0e7a3b9f10, is recommended. Do not derive the id from a name, an email address or a national identity number.

If a consultant changes name, or the file is moved, the id stays the same and consumers can keep following the same profile.

Availability and freshness

Availability is the information that ages fastest, so it is the main reason to read a profile again.

  • availability.status MUST be one of available, available-from, busy or unknown.
  • When the status is available-from, availableFrom MUST contain the first available date.
  • updatedAt MUST change whenever anything in the profile changes, including availability.
  • Publishers who do not want to state availability use unknown. Consumers MUST NOT present unknown as available.

Consumers SHOULD show when a profile was last updated and SHOULD read the entry file again regularly. Once a day is a reasonable default.

Human readable pages

The same information SHOULD also exist as an ordinary web page. Link the two together:

  • In the profile, set openconsultant.htmlUrl to the page.
  • On the page, point to the JSON with a link element:
<link rel="alternate" type="application/json" href="https://example.com/consultants/anna-andersson.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 GET request, without authentication, cookies or JavaScript.
  • The Content-Type MUST be application/json.
  • Files SHOULD allow cross-origin reads by sending Access-Control-Allow-Origin: *.
  • Files MUST be encoded as UTF-8.

Reading profiles

A consumer finds and reads a publisher’s profiles in three steps.

  1. Fetch https://<domain>/openconsultant.json.
  2. Check that standard is OpenConsultant and that it understands the schemaVersion.
  3. Fetch each url in consultants. Use updatedAt to skip profiles that have not changed.

Consumers:

  • MUST ignore fields they do not recognise.
  • MUST stop presenting a profile that has disappeared from the entry file.
  • MUST keep canonicalUrl with every copy and, wherever they present the profile, link back to the original: to htmlUrl when there is one, otherwise to canonicalUrl.
  • MUST name the publishing company as the source, and MUST NOT present themselves as the origin of the profile.
  • MUST replace their copy when the original changes, and SHOULD NOT alter the content they present.
  • SHOULD direct enquiries to openconsultant.contact.
  • SHOULD identify themselves with a descriptive User-Agent.

Consumers MAY add their own services around a profile, such as matching, evaluation 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-hourlyRateBand.

Versioning

  • Versions follow Semantic Versioning. This is 0.1.0.
  • schemaVersion states 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

A profile describes a person, and everything published according to this standard is public. The publisher is the one who decides what to publish and is responsible for doing it lawfully. That is the point of publishing at the source: the company that owns the information stays in control of it.

Personal data. Within the EU and EEA the GDPR applies. The publisher needs a legal basis for publishing, such as the consultant’s consent or another basis that fits the situation, and must have told the consultant clearly what is published, where and why. OpenConsultant does not provide that basis. It only describes the format.

Contact details. No private contact details are required. basics.email and basics.phone are optional and are best left out. Use openconsultant.contact to route enquiries through the company.

What not to publish. Do not publish national identity numbers, home addresses, dates of birth, salary or rate agreements, client names covered by confidentiality, or anything else the consultant or a client has not agreed to make public. Never put secrets, API keys or internal identifiers from business systems in a profile.

Updating and unpublishing. When a consultant leaves, or withdraws their agreement, remove the profile from the entry file and stop serving the profile file. A removed file SHOULD answer with HTTP 404 or 410.

Reuse. Consumers that index or present profiles are responsible for their own processing of personal data. They MUST follow removals, MUST link back to the original, SHOULD refresh copies regularly and SHOULD NOT keep a profile after the publisher has withdrawn it.