Create Project
POST /tm/v1/projects
Operation id: createProject
Description
Creates a new project entity with optional tasks and feedback questionnaires, and rolls it out to the specified organizational units.
Required permission: projects:create
Business Rules
Many fields and features are controlled by the project type configuration — a set of properties configured per project type in the admin UI. The server validates all fields against this configuration and returns 422 Unprocessable Entity when business rules are violated.
Key project type properties that affect validation:
| Property | Effect |
|---|---|
| "Define Tasks?" / "Mandatory Tasks?" | Whether tasks array can or must be included |
| "Allow Project Notes and Attachments?" / "Notes are mandatory" | Whether description is required |
| "Allow Project Tags?" | Whether tags are persisted |
| "Allow multiple assignments at project level?" | Single vs multiple entries in assignees.role_departments |
| "Collect working days required for the project?" | Whether schedule.working_days is required |
| "Auto complete project?" / "Configurable at project level" | Whether auto_complete_days is honored |
| "Confidential?" / "Configurable at project level" | Whether is_confidential is honored |
| "Allow user to collect feedback on project/task completion?" | Whether feedback_questions / external_form are accepted |
| "Collect project identifier?" | Whether ref_id is persisted |
| "Allow efforts to be defined at project level?" | Whether effort_minutes is accepted |
| "Time-sensitive project? -> Configurable at project level" | Whether schedule.is_time_sensitive is honored |
Validation Constraints
feedback_questionsandexternal_formare mutually exclusive — provide one or neither.- When task-level efforts are provided, their sum must not exceed project-level
effort_minutes. - Task scheduling mode 2:
start_day + days_required - 1must not exceedschedule.working_days. schedule.start_atandschedule.finish_atmust not be in the past and must not exceed the max fiscal calendar date.- All
role_id+department_idcombinations inassigneesmust be valid and active at the project's execution level. - Rollout units must exist at the specified
execution_level. Idempotency-Keyheader is required; reusing a key with a different payload returns409 Conflict.
Parameters
Header parameters
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string (uuid) | Yes | Prevents duplicate creations on network retries. Resubmitting the same key + payload returns the original 201 response. Keys expire after 24 hours. |
X-Request-Id | string (uuid) | No | Client-generated correlation ID for distributed tracing. Echoed in the response. |
Security
- ApiKeyAuth (apiKey)
- API key passed in the
apikeyrequest header.
- API key passed in the
Responses
201 — Project successfully created.
| Header | Description |
|---|---|
X-Request-Id | Echoed correlation ID from the request. |
Location | URI of the newly created project. |
Content type: application/json
400 — Validation error. Required fields missing, invalid dates, or malformed JSON.
Content type: application/json
401 — Missing or invalid authentication.
Content type: application/json
403 — Authenticated but insufficient permissions.
Content type: application/json
409 — Idempotency-Key reused with a different request payload.
Content type: application/json
422 — Request is syntactically valid but violates business rules.
Content type: application/json
429 — Request quota exceeded.
| Header | Description |
|---|---|
Retry-After | Seconds until the client may retry. |
Content type: application/json
500 — An unexpected server error occurred.
Content type: application/json
503 — The service is temporarily unavailable.
| Header | Description |
|---|---|
Retry-After | Estimated seconds until the service recovers. |
Content type: application/json
Request body
Required: Yes
application/json
Schema
| Property | Type | Required | Description |
|---|---|---|---|
template_id | string | No | Project ID of an existing project marked as a template. Base data (tasks, feedback, attachments, rollout, assignments, etc.) is copied from this project. Omit to create from scratch. |
title | string | Yes | Short, human-readable project name. HTML entities are unescaped and processed on ingestion. For recurring project types, the system may append a frequency suffix (e.g., "Weekly"), so keep titles under ~240 characters to avoid truncation. |
type | string | Yes | Project type code (2-4 uppercase letters or digits). Must match an active project type configured in the system. |
execution_level | integer | No | Organizational hierarchy level number at which this project is executed (1 = Corporate level, max = store level). Defaults to the maximum org level (store) if omitted. |
description | string | No | Rich-text body (project notes). Supports a safe subset of HTML and Markdown. May be mandatory depending on project type configuration. |
category | string | No | Primary category for the project. Must match a category defined in the project type configuration. |
subcategory | string | No | Subcategory within the primary category. Validated in combination with category. |
priority | integer | No | Priority ID (typically 1-4). Defaults to the project type's configured default priority if omitted. |
tags | array | No | Free-form labels for filtering and search. Only persisted when the project type property "Allow Project Tags?" is enabled. |
is_confidential | boolean | No | Restricts project visibility to assigned users only. Only honored when the project type allows override. |
creator_department_id | string | No | Department ID of the project creator. If omitted, derived from the authenticated user's profile. |
schedule | object | No | Project schedule. finish_at is required for non-recurring project types. |
recurrence | object | No | Defines a repeating schedule for REP type projects. Omit entirely for one-time projects. |
assignees | object | Yes | Defines who is responsible for the project or task using role-department intersection logic. |
rollout | array | No | Where the project applies. Each rule defines a set of organizational units. Defaults to the creator's own unit if omitted. |
attachments | array | No | File or URL attachments for the project. |
tasks | array | No | Ordered list of tasks within the project. At least one task is required when the project type property "Mandatory Tasks?" is enabled. |
feedback_questions | array | No | Inline feedback questionnaire. Mutually exclusive with external_form. Only applicable when the project type property "Allow user to collect feedback on project completion?" is enabled. |
external_form | object | No | Reference to an externally managed form/questionnaire. Mutually exclusive with feedback_questions. |
effort_minutes | integer | No | Estimated effort to complete the project, in minutes. |
auto_complete_days | integer | No | Number of days after the finish date to auto-complete the project. Omit to disable. |
notifications | object | No | Email notification settings for the project. |
prerequisites | array | No | Answers to prerequisite questions defined by the project type. |
ref_id | string | No | Client-supplied reference identifier for the project (e.g., ERP work-order ID). |
metadata | object | No | Arbitrary key-value pairs for supplementary data. Maximum payload size is 8 KB. |
{
"type": "object",
"required": [
"title",
"type",
"assignees"
],
"properties": {
"template_id": {
"type": "string",
"description": "Project ID of an existing project marked as a template. Base data (tasks, feedback, attachments, rollout, assignments, etc.) is copied from this project. Omit to create from scratch."
},
"title": {
"type": "string",
"description": "Short, human-readable project name. HTML entities are unescaped and processed on ingestion. For recurring project types, the system may append a frequency suffix (e.g., \"Weekly\"), so keep titles under ~240 characters to avoid truncation."
},
"type": {
"type": "string",
"description": "Project type code (2-4 uppercase letters or digits). Must match an active project type configured in the system."
},
"execution_level": {
"type": "integer",
"description": "Organizational hierarchy level number at which this project is executed (1 = Corporate level, max = store level). Defaults to the maximum org level (store) if omitted."
},
"description": {
"type": "string",
"description": "Rich-text body (project notes). Supports a safe subset of HTML and Markdown. May be mandatory depending on project type configuration."
},
"category": {
"type": "string",
"description": "Primary category for the project. Must match a category defined in the project type configuration."
},
"subcategory": {
"type": "string",
"description": "Subcategory within the primary category. Validated in combination with `category`."
},
"priority": {
"type": "integer",
"description": "Priority ID (typically 1-4). Defaults to the project type's configured default priority if omitted."
},
"tags": {
"type": "array",
"description": "Free-form labels for filtering and search. Only persisted when the project type property \"Allow Project Tags?\" is enabled.",
"items": {
"type": "string"
}
},
"is_confidential": {
"type": "boolean",
"description": "Restricts project visibility to assigned users only. Only honored when the project type allows override.",
"default": false
},
"creator_department_id": {
"type": "string",
"description": "Department ID of the project creator. If omitted, derived from the authenticated user's profile."
},
"schedule": {
"type": "object",
"description": "Project schedule. `finish_at` is required for non-recurring project types.",
"properties": {
"start_at": {
"type": "string",
"format": "date-time",
"description": "Project start date-time (ISO 8601 UTC). Must not be in the past. Defaults to current server time if omitted."
},
"finish_at": {
"type": "string",
"format": "date-time",
"description": "Project finish date-time (ISO 8601 UTC). Must be after `start_at` and must not be in the past."
},
"visibility": {
"type": "object",
"description": "Controls when the project becomes visible in the user's feed. Not applicable for `REP` (recurring) type projects.",
"required": [
"mode"
],
"properties": {
"mode": {
"type": "string",
"description": "- `immediate`: Visible as soon as the project is created.\n- `overnight`: Visible after the next overnight processing run.\n- `on_specific_date`: Visible at the date-time specified in `visible_at`.\n- `days_before_start`: Visible N days before `start_at`, controlled by `day_offset`.\n",
"enum": [
"immediate",
"overnight",
"on_specific_date",
"days_before_start"
],
"default": "immediate"
},
"visible_at": {
"type": "string",
"format": "date-time",
"description": "Visibility date-time (ISO 8601 UTC). Required when mode is `on_specific_date`."
},
"day_offset": {
"type": "integer",
"description": "Number of days before `start_at` to make the project visible. Required when mode is `days_before_start`."
}
}
},
"working_days": {
"type": "integer",
"description": "Total number of working days for the project. Required when the project type property \"Collect working days required for the project?\" is enabled."
},
"is_time_sensitive": {
"type": "boolean",
"description": "Caller-supplied time-sensitive flag. Honoured only when the project type exposes a \"Time-sensitive project? -> Configurable at project level\" override."
}
}
},
"recurrence": {
"type": "object",
"description": "Defines a repeating schedule for `REP` type projects. Omit entirely for one-time projects.",
"required": [
"frequency",
"range_type"
],
"properties": {
"frequency": {
"type": "string",
"enum": [
"daily",
"weekly",
"monthly",
"yearly",
"bi_weekly",
"fiscal_daily",
"fiscal_weekly",
"fiscal_periodic",
"fiscal_quarterly",
"fiscal_yearly"
]
},
"interval": {
"type": "integer",
"description": "Repeat every N periods. Applicable for calendar-based frequencies.",
"default": 1
},
"days_of_week": {
"type": "array",
"items": {
"type": "string",
"enum": [
"mon",
"tue",
"wed",
"thu",
"fri",
"sat",
"sun"
]
}
},
"day_of_month": {
"type": "integer"
},
"week_index": {
"type": "string",
"enum": [
"first",
"second",
"third",
"fourth",
"last"
]
},
"month": {
"type": "integer",
"description": "Required for `yearly` frequency."
},
"range_type": {
"type": "string",
"description": "- `end_date`: Stops on `ends_at`.\n- `numbered`: Stops after `occurrences` instances.\n- `no_end`: Indefinite recurrence.\n",
"enum": [
"end_date",
"numbered",
"no_end"
]
},
"ends_at": {
"type": "string",
"format": "date-time",
"description": "Required when `range_type` is `end_date`."
},
"occurrences": {
"type": "integer",
"description": "Required when `range_type` is `numbered`."
}
}
},
"assignees": {
"type": "object",
"description": "Defines who is responsible for the project or task using role-department intersection logic.",
"required": [
"role_departments"
],
"properties": {
"role_departments": {
"type": "array",
"items": {
"type": "object",
"required": [
"role_id",
"department_id"
],
"properties": {
"role_id": {
"type": "string",
"description": "The role identifier. Must be a valid, active role at the project's execution level."
},
"department_id": {
"type": "string",
"description": "The department identifier. Must be a valid, active department at the project's execution level."
}
}
}
}
}
},
"rollout": {
"type": "array",
"description": "Where the project applies. Each rule defines a set of organizational units. Defaults to the creator's own unit if omitted.",
"items": {
"type": "object"
}
},
"attachments": {
"type": "array",
"description": "File or URL attachments for the project.",
"items": {
"type": "object"
}
},
"tasks": {
"type": "array",
"description": "Ordered list of tasks within the project. At least one task is required when the project type property \"Mandatory Tasks?\" is enabled.",
"items": {
"type": "object",
"description": "A task within the project with its own schedule, assignees, attachments, and feedback.",
"required": [
"ref_id",
"title"
],
"properties": {
"ref_id": {
"type": "string",
"description": "Client-supplied reference identifier. Must be unique within the project."
},
"title": {
"type": "string"
},
"priority": {
"type": "integer",
"description": "Task-level priority ID. Inherits from project priority if omitted."
},
"assignees": {
"type": "object",
"description": "Defines who is responsible for the project or task using role-department intersection logic.",
"required": [
"role_departments"
],
"properties": {
"role_departments": {
"type": "array",
"items": {
"type": "object",
"required": [
"role_id",
"department_id"
]
}
}
}
},
"schedule": {
"type": "object",
"description": "Task timing — two modes:\n- Mode 1 (Absolute): provide `start_at` and `finish_at`.\n- Mode 2 (Relative): provide `start_day` and `days_required` (relative to project working days).\n",
"properties": {
"start_at": {
"type": "string",
"format": "date-time"
},
"finish_at": {
"type": "string",
"format": "date-time"
},
"start_day": {
"type": "integer",
"description": "1-based day number within the project's working days."
},
"days_required": {
"type": "integer"
}
}
},
"effort_minutes": {
"type": "integer"
},
"attachments": {
"type": "array",
"items": {
"type": "object"
}
},
"feedback_questions": {
"type": "array",
"items": {
"type": "object"
}
},
"external_form": {
"type": "object",
"description": "Reference to an externally managed form/questionnaire. Mutually exclusive with `feedback_questions`.",
"required": [
"form_id",
"title"
],
"properties": {
"form_id": {
"type": "string"
},
"title": {
"type": "string"
}
}
},
"optional": {
"type": "object",
"description": "When present, this task only applies to stores matching the attribute conditions.",
"properties": {
"operator": {
"type": "string",
"enum": [
"and",
"or"
]
},
"conditions": {
"type": "array",
"items": {
"type": "object",
"required": [
"attribute_name",
"attribute_values"
]
}
}
}
}
}
}
},
"feedback_questions": {
"type": "array",
"description": "Inline feedback questionnaire. Mutually exclusive with `external_form`. Only applicable when the project type property \"Allow user to collect feedback on project completion?\" is enabled.",
"items": {
"type": "object"
}
},
"external_form": {
"type": "object",
"description": "Reference to an externally managed form/questionnaire. Mutually exclusive with `feedback_questions`.",
"required": [
"form_id",
"title"
],
"properties": {
"form_id": {
"type": "string"
},
"title": {
"type": "string"
}
}
},
"effort_minutes": {
"type": "integer",
"description": "Estimated effort to complete the project, in minutes."
},
"auto_complete_days": {
"type": "integer",
"description": "Number of days after the finish date to auto-complete the project. Omit to disable."
},
"notifications": {
"type": "object",
"description": "Email notification settings for the project.",
"properties": {
"email_addresses": {
"type": "array",
"items": {
"type": "string",
"format": "email"
}
},
"mailing_list_ids": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"prerequisites": {
"type": "array",
"description": "Answers to prerequisite questions defined by the project type.",
"items": {
"type": "object",
"description": "Answer to a prerequisite question defined by the project type.",
"required": [
"question_id",
"answer"
],
"properties": {
"question_id": {
"type": "integer"
},
"answer": {
"type": "string",
"description": "Format depends on question type:\n- Text (single-line): free-text string, max 200 characters.\n- Text (multi-line): free-text string, max 4000 characters.\n- Numeric: integer as a string (e.g., \"42\").\n- Yes/No: \"Y\" or \"N\".\n- Single choice: option number as a string (e.g., \"3\").\n- Multiple choice: comma-separated option numbers (e.g., \"1,3,5\").\n"
}
}
}
},
"ref_id": {
"type": "string",
"description": "Client-supplied reference identifier for the project (e.g., ERP work-order ID)."
},
"metadata": {
"type": "object",
"description": "Arbitrary key-value pairs for supplementary data. Maximum payload size is 8 KB."
}
}
}
Response models
201 — Project successfully created.
Content type: application/json
Schema
| Property | Type | Required | Description |
|---|---|---|---|
object | string | No | |
id | string | No | Unique project identifier. |
type | string | No | |
template_id | string | No | |
title | string | No | |
status | string | No | |
created_at | string (date-time) | No | |
url | string | No | Canonical API URL of the created project. |
ref_id | string | No | |
tasks | array | No |
{
"type": "object",
"properties": {
"object": {
"type": "string",
"enum": [
"project"
]
},
"id": {
"type": "string",
"description": "Unique project identifier."
},
"type": {
"type": "string"
},
"template_id": {
"type": "string"
},
"title": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"created",
"published",
"submitted"
]
},
"created_at": {
"type": "string",
"format": "date-time"
},
"url": {
"type": "string",
"description": "Canonical API URL of the created project."
},
"ref_id": {
"type": "string"
},
"tasks": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Server-generated unique identifier for this task."
},
"ref_id": {
"type": "string",
"description": "Echoed client-supplied reference ID from the request."
}
}
}
}
}
}
400 — Validation error. Required fields missing, invalid dates, or malformed JSON.
Content type: application/json
Schema
| Property | Type | Required | Description |
|---|---|---|---|
error | object | Yes |
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "object",
"required": [
"type",
"code",
"message"
],
"properties": {
"type": {
"type": "string",
"description": "High-level error category."
},
"code": {
"type": "string",
"description": "Machine-readable error code."
},
"message": {
"type": "string",
"description": "Human-readable message."
},
"param": {
"type": "string",
"description": "The specific field that caused the error (dot-notation path)."
},
"doc_url": {
"type": "string",
"format": "uri"
},
"errors": {
"type": "array",
"description": "Present when multiple fields have errors (batch validation).",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"param": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
}
}
}
Example:
{
"error": {
"type": "validation_error",
"code": "invalid_parameter",
"message": "One or more request parameters are invalid.",
"errors": [
{
"code": "required",
"param": "title",
"message": "The 'title' field is required."
},
{
"code": "invalid_format",
"param": "schedule.finish_at",
"message": "Must be a valid ISO 8601 UTC date-time."
}
]
}
}
401 — Missing or invalid authentication.
Content type: application/json
Schema
| Property | Type | Required | Description |
|---|---|---|---|
error | object | Yes |
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "object",
"required": [
"type",
"code",
"message"
],
"properties": {
"type": {
"type": "string",
"description": "High-level error category."
},
"code": {
"type": "string",
"description": "Machine-readable error code."
},
"message": {
"type": "string",
"description": "Human-readable message."
},
"param": {
"type": "string",
"description": "The specific field that caused the error (dot-notation path)."
},
"doc_url": {
"type": "string",
"format": "uri"
},
"errors": {
"type": "array",
"description": "Present when multiple fields have errors (batch validation).",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"param": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
}
}
}
Example:
{
"error": {
"type": "authentication_error",
"code": "unauthorized",
"message": "API key is missing or invalid in the 'apikey' request header."
}
}
403 — Authenticated but insufficient permissions.
Content type: application/json
Schema
| Property | Type | Required | Description |
|---|---|---|---|
error | object | Yes |
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "object",
"required": [
"type",
"code",
"message"
],
"properties": {
"type": {
"type": "string",
"description": "High-level error category."
},
"code": {
"type": "string",
"description": "Machine-readable error code."
},
"message": {
"type": "string",
"description": "Human-readable message."
},
"param": {
"type": "string",
"description": "The specific field that caused the error (dot-notation path)."
},
"doc_url": {
"type": "string",
"format": "uri"
},
"errors": {
"type": "array",
"description": "Present when multiple fields have errors (batch validation).",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"param": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
}
}
}
Example:
{
"error": {
"type": "authorization_error",
"code": "access_denied",
"message": "You do not have permission to perform this action."
}
}
409 — Idempotency-Key reused with a different request payload.
Content type: application/json
Schema
| Property | Type | Required | Description |
|---|---|---|---|
error | object | Yes |
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "object",
"required": [
"type",
"code",
"message"
],
"properties": {
"type": {
"type": "string",
"description": "High-level error category."
},
"code": {
"type": "string",
"description": "Machine-readable error code."
},
"message": {
"type": "string",
"description": "Human-readable message."
},
"param": {
"type": "string",
"description": "The specific field that caused the error (dot-notation path)."
},
"doc_url": {
"type": "string",
"format": "uri"
},
"errors": {
"type": "array",
"description": "Present when multiple fields have errors (batch validation).",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"param": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
}
}
}
Example:
{
"error": {
"type": "idempotency_error",
"code": "idempotency_key_reused",
"message": "This Idempotency-Key has already been used with a different request payload."
}
}
422 — Request is syntactically valid but violates business rules.
Content type: application/json
Schema
| Property | Type | Required | Description |
|---|---|---|---|
error | object | Yes |
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "object",
"required": [
"type",
"code",
"message"
],
"properties": {
"type": {
"type": "string",
"description": "High-level error category."
},
"code": {
"type": "string",
"description": "Machine-readable error code."
},
"message": {
"type": "string",
"description": "Human-readable message."
},
"param": {
"type": "string",
"description": "The specific field that caused the error (dot-notation path)."
},
"doc_url": {
"type": "string",
"format": "uri"
},
"errors": {
"type": "array",
"description": "Present when multiple fields have errors (batch validation).",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"param": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
}
}
}
429 — Request quota exceeded.
Content type: application/json
Schema
| Property | Type | Required | Description |
|---|---|---|---|
error | object | Yes |
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "object",
"required": [
"type",
"code",
"message"
],
"properties": {
"type": {
"type": "string",
"description": "High-level error category."
},
"code": {
"type": "string",
"description": "Machine-readable error code."
},
"message": {
"type": "string",
"description": "Human-readable message."
},
"param": {
"type": "string",
"description": "The specific field that caused the error (dot-notation path)."
},
"doc_url": {
"type": "string",
"format": "uri"
},
"errors": {
"type": "array",
"description": "Present when multiple fields have errors (batch validation).",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"param": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
}
}
}
Example:
{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"message": "Too many requests. Please try again later."
}
}
500 — An unexpected server error occurred.
Content type: application/json
Schema
| Property | Type | Required | Description |
|---|---|---|---|
error | object | Yes |
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "object",
"required": [
"type",
"code",
"message"
],
"properties": {
"type": {
"type": "string",
"description": "High-level error category."
},
"code": {
"type": "string",
"description": "Machine-readable error code."
},
"message": {
"type": "string",
"description": "Human-readable message."
},
"param": {
"type": "string",
"description": "The specific field that caused the error (dot-notation path)."
},
"doc_url": {
"type": "string",
"format": "uri"
},
"errors": {
"type": "array",
"description": "Present when multiple fields have errors (batch validation).",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"param": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
}
}
}
Example:
{
"error": {
"type": "server_error",
"code": "internal_error",
"message": "An unexpected error occurred while processing the request."
}
}
503 — The service is temporarily unavailable.
Content type: application/json
Schema
| Property | Type | Required | Description |
|---|---|---|---|
error | object | Yes |
{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "object",
"required": [
"type",
"code",
"message"
],
"properties": {
"type": {
"type": "string",
"description": "High-level error category."
},
"code": {
"type": "string",
"description": "Machine-readable error code."
},
"message": {
"type": "string",
"description": "Human-readable message."
},
"param": {
"type": "string",
"description": "The specific field that caused the error (dot-notation path)."
},
"doc_url": {
"type": "string",
"format": "uri"
},
"errors": {
"type": "array",
"description": "Present when multiple fields have errors (batch validation).",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"param": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
}
}
}
}
}
Example:
{
"error": {
"type": "server_error",
"code": "service_unavailable",
"message": "The service is temporarily unavailable. Please try again later."
}
}