Skip to content
OpenTrain AIOpenTrain AIOpenTrain AIDocs

Ask OpenTrain

Answers from the documentation, with sources.

What would you like to do with OpenTrain?

AI answers can be mistaken. Check the linked sources. Don’t include private account information.

Open app

DEVELOPER DOCUMENTATION

Create Job Draft

Create a job draft from a natural-language description and receive validation prompts for missing fields.

POST/api/public/v1/job-drafts

Creates an unpublished job draft. The description-first workflow: send a plain-text job description, OpenTrain parses it into structured fields server-side, and the response tells you exactly what is still missing — each missing field carries a ready-to-ask prompt, its type, allowed enumValues, and the updateKeys to patch via PATCH /job-drafts/{jobId}. Loop until validation.publishReady is true, then publish.

Structured imports (schema.org JSON-LD, Indeed-style XML, HR-XML, or OpenTrain’s canonical job object) are also accepted. See the posting guide for the full loop.

Requirements: jobs:write scope + the public_api_job_drafting feature (check capabilities).

Send one of the body shapes below. All are JSON objects.

rawJobDescriptionstringbody

Plain-text job description or project brief (max 60,000 characters). The simplest and recommended input — OpenTrain parses it into structured fields. Equivalent shorthand for source: {type: "text", text: ...}.

sourceobjectbody

Structured import source.

source fields
source.typestringbody

Import format: text, opentrain_canonical, schema_org_job_posting, indeed_xml, or hr_xml. Unsupported values return 400 with details.supportedFormats.

source.textstringbody

The text or serialized payload for the chosen format.

source.externalIdstringbody

Source-system identifier for audit (max 256 characters).

source.idempotencyKeystringbody

Reuse the same key on retries to avoid duplicate drafts (max 256 characters).

formatstringbody

Top-level alternative to source.type — same supported values. Pair with job (canonical), jsonLd (schema.org), or xml (feeds).

jobobjectbody

OpenTrain canonical job object when format is opentrain_canonical — keys like title, description, paymentType, rateAmount, languages, countries, labelTypes, tools, experienceLevel.

externalIdstringbody

Top-level equivalent of source.externalId.

idempotencyKeystringbody

Top-level equivalent of source.idempotencyKey.

okboolean

true on success.

jobIdstring

The new draft’s job ID — use it for every subsequent PATCH and the publish call.

statusstring

Always DRAFT (this endpoint never auto-publishes).

draftUrlstring

In-app URL of the draft editor.

reviewUrlstring

In-app URL where a human can review the draft.

validationobject

Publish-readiness summary.

validation fields
publishReadyboolean

true when the draft can be published as-is.

issueCountnumber

Number of blocking issues.

missingFieldCountnumber

Number of required fields still missing.

missingFieldsobject[]

Same entries as the top-level missingFields.

issuesobject[]

Non-field-specific validation issues.

missingFieldsobject[]

The gap-filling work list. Relay each prompt to your human, then patch the answer.

missingFields entry
fieldstring

Internal field identifier.

labelstring

Human-readable field name.

messagestring

Why the field is required.

codestring

Machine-readable issue code.

promptstring

A ready-to-ask question (e.g. "ask: What experience level should AI trainers have?").

typestring

Expected answer type — string, number, enum, string[], etc.

enumValuesstring[] | null

Allowed values when type is enum. Patch with one of these exact values.

updateKeysstring[]

The key(s) to set in the PATCH body (e.g. ["paymentType", "pricePerHour"]).

examplestring | null

Example value.

hintstring | null

Extra guidance for answering.

normalizedFieldsobject

The structured fields OpenTrain extracted from your input.

warningsstring[]

Non-blocking warnings.

unmappedFieldsobject[]

Input keys that could not be mapped — {path, reason, valuePreview}.

lowConfidenceFieldsobject[]

Parsed fields worth double-checking with your human — {path, reason}.

importobject

Audit echo: {format, externalId, idempotencyKey, rawSourcePreserved, autoPublished: false}.

parserobject

Parser metadata: {source, warnings, parsedFields}.

StatuscodeMeaning
400BAD_REQUESTEmpty body, invalid JSON, unsupported format (details.supportedFormats), or description over 60,000 characters
401UNAUTHORIZEDMissing or invalid token
403FORBIDDENMissing jobs:write scope (details.requiredScopes) or public_api_job_drafting disabled (details.featureKey)