{
  "openapi": "3.1.1",
  "info": {
    "title": "Kinetica API",
    "version": "1.0.0",
    "summary": "Deterministic tools for people and AI agents.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://kinetica.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "Catalog of all tools",
        "responses": {
          "200": {
            "description": "Tool list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/{id}": {
      "get": {
        "operationId": "getTool",
        "summary": "Definition of one tool",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "kinetica-forward-kinematics",
                "kinetica-inverse-kinematics",
                "kinetica-trajectory-planner",
                "kinetica-collision-check"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/kinetica-forward-kinematics/calculate": {
      "post": {
        "operationId": "calculateKineticaForwardKinematics",
        "summary": "DH table or URDF + joint values → TCP pose, every joint frame, Jacobian and manipulability.",
        "description": "Computes the tool-centre-point pose of a serial robot from its Denavit–Hartenberg table (standard or modified), a URDF subset or a library robot and the joint values. Returns the 4×4 transform, position and roll/pitch/yaw, quaternion, all intermediate frames, the geometric Jacobian, manipulability and singularity status, and static payload torques.\n\nMethodology:\n- Each joint compiles to Fᵢ = Fᵢ₋₁ · Preᵢ · Motionᵢ(qᵢ) · Postᵢ. Standard DH: Rz(θ+q)·Tz(d)·Tx(a)·Rx(α); modified DH (Craig): Rx(α)·Tx(a)·Rz(θ+q)·Tz(d); URDF: origin(xyz, rpy) · rotation about / translation along the joint axis.\n- TCP = base mount · F_n · tool offset. Orientation is reported as fixed-axis roll-pitch-yaw (R = Rz(yaw)·Ry(pitch)·Rx(roll), the URDF convention) and as a unit quaternion [w, x, y, z].\n- Geometric Jacobian at the TCP: revolute column [zᵢ × (p − oᵢ); zᵢ], prismatic column [zᵢ; 0]. Rows vx, vy, vz in mm per rad (or per mm), wx, wy, wz in rad per unit.\n- Manipulability: Yoshikawa √det(J·Jᵀ) of the Jacobian with translation rows divided by a characteristic length (the arm’s skeleton length), and σmin/σmax as a 0–1 singularity indicator (< 0.001 singular, < 0.03 near-singular).\n- Payload loads: static holding torque τ = −Jᵀ(cog)·m·g for the tool mass at its centre of gravity (g = 9.80665 m/s², gravity along −z world).\n- Verified against hand-computed planar cases, the PUMA 560 qz pose (452.1, −150.05, 1103.63) mm of the Robotics Toolbox model and the UR5 zero pose (−817.25, −191.45, −5.491) mm.\n\nKinematic simulation for planning and teaching. It is not a certified safety function: verify every program on the real controller with reduced speed and the cell safety system active.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kinetica_forward_kinematics",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KineticaForwardKinematicsInput"
              },
              "examples": {
                "example1": {
                  "summary": "PUMA 560 at qz (all zeros) — textbook pose",
                  "value": {
                    "robot": "puma560",
                    "joints": "0, 0, 0, 0, 0, 0"
                  }
                },
                "example2": {
                  "summary": "UR5-style cobot at its upright home",
                  "value": {
                    "robot": "ur5-like",
                    "joints": "0, -90, 90, -90, -90, 0"
                  }
                },
                "example3": {
                  "summary": "Planar 2-link arm from a custom DH table (l1 = 300, l2 = 250)",
                  "value": {
                    "robot": "custom-dh",
                    "convention": "dh",
                    "dh": [
                      {
                        "type": "revolute",
                        "a": 300,
                        "alpha": 0,
                        "d": 0,
                        "theta": 0
                      },
                      {
                        "type": "revolute",
                        "a": 250,
                        "alpha": 0,
                        "d": 0,
                        "theta": 0
                      }
                    ],
                    "joints": "30, 60"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KineticaForwardKinematicsResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/kinetica-inverse-kinematics/calculate": {
      "post": {
        "operationId": "calculateKineticaInverseKinematics",
        "summary": "Target TCP pose → all joint solutions found, residuals, joint limits and reachability.",
        "description": "Solves the inverse kinematics of a serial robot (DH table, URDF subset or library robot) for a target TCP pose with damped least squares from several deterministic seeds, plus closed-form solutions for planar 2-link arms and SCARAs. Lists every distinct solution with its residual, joint-limit and singularity status, and explains why a target is unreachable.\n\nMethodology:\n- Error e = [Δp / L; Δφ] with Δφ the rotation vector from current to target orientation and L the arm’s characteristic length, restricted to the task rows the robot can actually control (e.g. x, y, z, yaw for a SCARA; x, y for a planar arm).\n- Damped least squares step Δq = Jᵀ(J·Jᵀ + λ²I)⁻¹e with adaptive damping λ (decrease after an improving step, increase after a failed one), step-size limit 0.5 rad, and projection onto the joint limits (revolute joints wrap by 2π when the range allows).\n- Restarts: the preferred configuration, the home pose, then pseudo-random configurations from a seeded mulberry32 generator; distinct converged solutions (position residual ≤ 1e-6 mm, orientation ≤ 1e-8 rad) are kept and sorted by distance to the preferred configuration.\n- Closed forms: planar 2R and SCARA use the law of cosines (two elbow branches), then FK verifies and a short DLS polish removes any remaining residual.\n- Unreachable targets report the distance from the first joint versus the skeleton length (upper bound of reach) and the closest configuration found.\n\nKinematic simulation for planning and teaching. It is not a certified safety function: verify every program on the real controller with reduced speed and the cell safety system active.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kinetica_inverse_kinematics",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KineticaInverseKinematicsInput"
              },
              "examples": {
                "example1": {
                  "summary": "6-axis arm, tool pointing down at (700, 200, 600) mm",
                  "value": {
                    "robot": "kx6-1400",
                    "x": 700,
                    "y": 200,
                    "z": 600,
                    "roll": 180,
                    "pitch": 0,
                    "yaw": 0
                  }
                },
                "example2": {
                  "summary": "SCARA closed form: (300, 250, 200) mm, yaw 45°",
                  "value": {
                    "robot": "scara-550",
                    "x": 300,
                    "y": 250,
                    "z": 200,
                    "roll": 180,
                    "pitch": 0,
                    "yaw": 45
                  }
                },
                "example3": {
                  "summary": "Planar arm: elbow-up and elbow-down for (350, 200)",
                  "value": {
                    "robot": "planar2",
                    "x": 350,
                    "y": 200,
                    "z": 50,
                    "roll": 0,
                    "pitch": 0,
                    "yaw": 0,
                    "mode": "position"
                  }
                },
                "example4": {
                  "summary": "Unreachable target (2 m away)",
                  "value": {
                    "robot": "ur5-like",
                    "x": 2000,
                    "y": 0,
                    "z": 300,
                    "roll": 180,
                    "pitch": 0,
                    "yaw": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KineticaInverseKinematicsResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/kinetica-trajectory-planner/calculate": {
      "post": {
        "operationId": "calculateKineticaTrajectoryPlanner",
        "summary": "Waypoints (PTP, LIN, CIRC) + limits → timed joint samples, cycle time and peak velocities.",
        "description": "Plans a robot motion program from waypoints: synchronous joint moves (PTP), straight TCP lines (LIN) and circular arcs (CIRC) with trapezoidal, quintic or jerk-limited S-curve profiles that respect the joint velocity and acceleration limits, blend radii and dwell times. Returns the cycle time, per-segment timing, peak joint velocities and accelerations, a sampled joint/TCP trajectory and a CSV.\n\nMethodology:\n- PTP: synchronous joint interpolation q(s) = q₀ + s·Δq with one profile on s ∈ [0, 1]; the limits on s are min over joints of vmaxᵢ/|Δqᵢ| (and the same for acceleration and jerk), so every joint starts and stops together and none exceeds its limits.\n- Trapezoid: if h ≥ v²/a then Ta = v/a and T = h/v + v/a, else triangular with Ta = √(h/a), T = 2√(h/a). Quintic: s = 10τ³ − 15τ⁴ + 6τ⁵ with T = max(1.875·h/v, √(5.7735·h/a)). S-curve: double-S with jerk limit (Biagiotti & Melchiorri §3.4).\n- LIN/CIRC: the TCP follows the line or the circle through start, via and end point, orientation by quaternion slerp; IK runs per sample seeded from the previous one. If a joint would exceed its velocity/acceleration limit the segment is slowed down uniformly and re-planned (reported as speed scale).\n- Blending: consecutive moves overlap by the time the TCP spends inside the blend radius (capped at half of each move) and are superposed in joint space, which rounds the corner without stopping.\n- Velocities/accelerations in the output are central differences of the sampled trajectory; the cycle time includes dwell times.\n\nKinematic simulation for planning and teaching. It is not a certified safety function: verify every program on the real controller with reduced speed and the cell safety system active. Real controllers add their own look-ahead, dynamics limits and servo lag, so measured cycle times differ.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kinetica_trajectory_planner",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KineticaTrajectoryPlannerInput"
              },
              "examples": {
                "example1": {
                  "summary": "6-axis arm: two PTP moves and a LIN line",
                  "value": {
                    "robot": "kx6-1400",
                    "profile": "trapezoid",
                    "waypoints": [
                      {
                        "name": "Home",
                        "type": "PTP",
                        "target": "j: 0, 0, 0, 0, 90, 0"
                      },
                      {
                        "name": "Above",
                        "type": "PTP",
                        "target": "p: 800, -200, 700, 180, 0, 0",
                        "vel": 80,
                        "acc": 80,
                        "blend": 30
                      },
                      {
                        "name": "Line",
                        "type": "LIN",
                        "target": "p: 800, 200, 700, 180, 0, 0",
                        "vel": 250,
                        "acc": 1500
                      },
                      {
                        "name": "Home",
                        "type": "PTP",
                        "target": "j: 0, 0, 0, 0, 90, 0",
                        "vel": 100,
                        "acc": 100
                      }
                    ]
                  }
                },
                "example2": {
                  "summary": "Single joint, trapezoid timing check (90° at 156°/s, 400°/s²)",
                  "value": {
                    "robot": "kx6-1400",
                    "profile": "trapezoid",
                    "waypoints": [
                      {
                        "name": "A",
                        "type": "PTP",
                        "target": "j: 0, 0, 0, 0, 90, 0"
                      },
                      {
                        "name": "B",
                        "type": "PTP",
                        "target": "j: 90, 0, 0, 0, 90, 0",
                        "vel": 100,
                        "acc": 100
                      }
                    ]
                  }
                },
                "example3": {
                  "summary": "SCARA pick with S-curve profile and CIRC",
                  "value": {
                    "robot": "scara-550",
                    "profile": "scurve",
                    "waypoints": [
                      {
                        "name": "Start",
                        "type": "PTP",
                        "target": "j: -30, 60, 50, 0"
                      },
                      {
                        "name": "P1",
                        "type": "LIN",
                        "target": "p: 350, -200, 250, 180, 0, 0",
                        "vel": 500,
                        "acc": 4000
                      },
                      {
                        "name": "Arc",
                        "type": "CIRC",
                        "target": "p: 350, 200, 250, 180, 0, 0",
                        "via": "450, 0, 250",
                        "vel": 500,
                        "acc": 4000
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KineticaTrajectoryPlannerResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tools/kinetica-collision-check/calculate": {
      "post": {
        "operationId": "calculateKineticaCollisionCheck",
        "summary": "Robot pose + obstacles → collisions, minimum clearance and self-collision between links.",
        "description": "Checks a robot configuration against box, sphere and capsule obstacles and against itself. Robot links are modelled as capsules and boxes; the tool reports every pair closer than the safety margin, the minimum clearance and the closest pair, using exact segment–segment distances and an exact convex search for capsule–box distances.\n\nMethodology:\n- Robot links are capsules (segment + radius) and oriented boxes attached to the link frames; library robots generate capsules along the kinematic skeleton, URDF boxes/cylinders/spheres are imported (cylinders become capsules with caps ending at the cylinder faces; flat discs become an equal-area square prism).\n- Capsule–capsule: closest points between two segments minus both radii. Capsule–box: the squared distance from the segment to the box is convex in the segment parameter, so a 64-step golden-section search finds the minimum. Box–box: separating-axis test for overlap, else the minimum of the 24 edge-to-box distances.\n- Self-collision skips adjacent links, user-listed pairs and pairs that already touch in the robot’s home pose (as in MoveIt’s allowed-collision matrix); the static base link is not checked against the environment.\n- A pair counts as a contact when its clearance is below the safety margin.\n\nKinematic simulation for planning and teaching. It is not a certified safety function: verify every program on the real controller with reduced speed and the cell safety system active. Geometry is a simplified envelope of the real robot.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "kinetica_collision_check",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KineticaCollisionCheckInput"
              },
              "examples": {
                "example1": {
                  "summary": "6-axis arm above a table (clear)",
                  "value": {
                    "robot": "kx6-1400",
                    "joints": "0, 0, 0, 0, 90, 0",
                    "obstacles": [
                      {
                        "name": "Table",
                        "shape": "box",
                        "x": 900,
                        "y": 0,
                        "z": 350,
                        "sx": 700,
                        "sy": 900,
                        "sz": 700
                      }
                    ],
                    "margin": 10
                  }
                },
                "example2": {
                  "summary": "Arm reaching into a box (collision)",
                  "value": {
                    "robot": "kx6-1400",
                    "joints": "0, 40, 30, 0, 20, 0",
                    "obstacles": [
                      {
                        "name": "Machine",
                        "shape": "box",
                        "x": 1000,
                        "y": 0,
                        "z": 400,
                        "sx": 600,
                        "sy": 800,
                        "sz": 800
                      }
                    ],
                    "margin": 0
                  }
                },
                "example3": {
                  "summary": "Folded elbow: self-collision check",
                  "value": {
                    "robot": "kx6-1400",
                    "joints": "0, -90, 155, 0, 125, 0",
                    "self": true,
                    "margin": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KineticaCollisionCheckResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/workflows": {
      "get": {
        "operationId": "listWorkflows",
        "summary": "Multi-tool workflows",
        "responses": {
          "200": {
            "description": "Workflow list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "KineticaForwardKinematicsInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "robot": {
            "title": "Robot",
            "description": "A library robot, or choose a custom DH table, URDF or Kinetica robot JSON.",
            "type": "string",
            "enum": [
              "kx6-1400",
              "ur5-like",
              "puma560",
              "scara-550",
              "gantry-xyz",
              "planar2",
              "custom-dh",
              "urdf",
              "json"
            ],
            "default": "kx6-1400"
          },
          "convention": {
            "title": "DH convention (custom table)",
            "type": "string",
            "enum": [
              "dh",
              "mdh"
            ],
            "default": "dh"
          },
          "dh": {
            "title": "DH table (custom)",
            "description": "One row per joint. Lengths in mm, angles in degrees. For revolute joints θ is the zero offset, for prismatic joints d is.",
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "revolute",
                    "prismatic"
                  ],
                  "default": "revolute"
                },
                "a": {
                  "title": "a (mm)",
                  "type": "number",
                  "default": 0
                },
                "alpha": {
                  "title": "α (deg)",
                  "type": "number",
                  "default": 0
                },
                "d": {
                  "title": "d (mm)",
                  "type": "number",
                  "default": 0
                },
                "theta": {
                  "title": "θ (deg)",
                  "type": "number",
                  "default": 0
                },
                "min": {
                  "title": "min",
                  "type": "number"
                },
                "max": {
                  "title": "max",
                  "type": "number"
                },
                "vmax": {
                  "title": "v max (/s)",
                  "type": "number"
                },
                "amax": {
                  "title": "a max (/s²)",
                  "type": "number"
                }
              },
              "required": []
            }
          },
          "robotText": {
            "title": "URDF or robot JSON",
            "description": "Used when Robot is “URDF” or “Kinetica robot JSON”. URDF subset: links with box/cylinder/sphere, revolute/continuous/prismatic/fixed joints.",
            "type": "string",
            "maxLength": 400000
          },
          "tool": {
            "title": "Tool offset (TCP)",
            "description": "x, y, z (mm), roll, pitch, yaw (deg) in the flange frame, e.g. “0, 0, 150, 0, 0, 0”. Empty = robot default.",
            "type": "string",
            "default": ""
          },
          "joints": {
            "title": "Joint values",
            "description": "Comma-separated, degrees for revolute and mm for prismatic joints. Empty = the robot’s home pose.",
            "type": "string",
            "default": ""
          }
        },
        "required": []
      },
      "KineticaForwardKinematicsResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "required": [
              "robot",
              "dof",
              "joints",
              "tcp",
              "matrix",
              "frames",
              "jacobian",
              "manipulability",
              "withinLimits"
            ],
            "properties": {
              "robot": {
                "type": "string"
              },
              "dof": {
                "type": "integer"
              },
              "joints": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "value": {
                      "type": "number"
                    },
                    "unit": {
                      "type": "string"
                    }
                  }
                }
              },
              "tcp": {
                "type": "object",
                "properties": {
                  "x": {
                    "type": "number"
                  },
                  "y": {
                    "type": "number"
                  },
                  "z": {
                    "type": "number"
                  },
                  "roll": {
                    "type": "number"
                  },
                  "pitch": {
                    "type": "number"
                  },
                  "yaw": {
                    "type": "number"
                  },
                  "quat": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  }
                },
                "required": [
                  "x",
                  "y",
                  "z",
                  "roll",
                  "pitch",
                  "yaw",
                  "quat"
                ]
              },
              "flange": {
                "type": "object",
                "properties": {
                  "x": {
                    "type": "number"
                  },
                  "y": {
                    "type": "number"
                  },
                  "z": {
                    "type": "number"
                  },
                  "roll": {
                    "type": "number"
                  },
                  "pitch": {
                    "type": "number"
                  },
                  "yaw": {
                    "type": "number"
                  },
                  "quat": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  }
                },
                "required": [
                  "x",
                  "y",
                  "z",
                  "roll",
                  "pitch",
                  "yaw",
                  "quat"
                ]
              },
              "matrix": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              },
              "frames": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              },
              "jacobian": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              },
              "manipulability": {
                "type": "object",
                "properties": {
                  "yoshikawa": {
                    "type": "number"
                  },
                  "inverseCondition": {
                    "type": "number"
                  },
                  "status": {
                    "type": "string"
                  }
                }
              },
              "payloadLoads": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "withinLimits": {
                "type": "boolean"
              },
              "violatedJoints": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "KineticaInverseKinematicsInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "robot": {
            "title": "Robot",
            "description": "A library robot, or choose a custom DH table, URDF or Kinetica robot JSON.",
            "type": "string",
            "enum": [
              "kx6-1400",
              "ur5-like",
              "puma560",
              "scara-550",
              "gantry-xyz",
              "planar2",
              "custom-dh",
              "urdf",
              "json"
            ],
            "default": "kx6-1400"
          },
          "convention": {
            "title": "DH convention (custom table)",
            "type": "string",
            "enum": [
              "dh",
              "mdh"
            ],
            "default": "dh"
          },
          "dh": {
            "title": "DH table (custom)",
            "description": "One row per joint. Lengths in mm, angles in degrees. For revolute joints θ is the zero offset, for prismatic joints d is.",
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "revolute",
                    "prismatic"
                  ],
                  "default": "revolute"
                },
                "a": {
                  "title": "a (mm)",
                  "type": "number",
                  "default": 0
                },
                "alpha": {
                  "title": "α (deg)",
                  "type": "number",
                  "default": 0
                },
                "d": {
                  "title": "d (mm)",
                  "type": "number",
                  "default": 0
                },
                "theta": {
                  "title": "θ (deg)",
                  "type": "number",
                  "default": 0
                },
                "min": {
                  "title": "min",
                  "type": "number"
                },
                "max": {
                  "title": "max",
                  "type": "number"
                },
                "vmax": {
                  "title": "v max (/s)",
                  "type": "number"
                },
                "amax": {
                  "title": "a max (/s²)",
                  "type": "number"
                }
              },
              "required": []
            }
          },
          "robotText": {
            "title": "URDF or robot JSON",
            "description": "Used when Robot is “URDF” or “Kinetica robot JSON”. URDF subset: links with box/cylinder/sphere, revolute/continuous/prismatic/fixed joints.",
            "type": "string",
            "maxLength": 400000
          },
          "tool": {
            "title": "Tool offset (TCP)",
            "description": "x, y, z (mm), roll, pitch, yaw (deg) in the flange frame, e.g. “0, 0, 150, 0, 0, 0”. Empty = robot default.",
            "type": "string",
            "default": ""
          },
          "x": {
            "title": "Target x",
            "type": "number",
            "default": 700,
            "x-unit": "mm"
          },
          "y": {
            "title": "Target y",
            "type": "number",
            "default": 200,
            "x-unit": "mm"
          },
          "z": {
            "title": "Target z",
            "type": "number",
            "default": 600,
            "x-unit": "mm"
          },
          "roll": {
            "title": "Roll",
            "type": "number",
            "default": 180,
            "x-unit": "deg"
          },
          "pitch": {
            "title": "Pitch",
            "type": "number",
            "default": 0,
            "x-unit": "deg"
          },
          "yaw": {
            "title": "Yaw",
            "type": "number",
            "default": 0,
            "x-unit": "deg"
          },
          "mode": {
            "title": "Task",
            "type": "string",
            "enum": [
              "auto",
              "full",
              "position"
            ],
            "default": "auto"
          },
          "seed": {
            "title": "Preferred configuration",
            "description": "Joint values the solutions are sorted by (closest first). Empty = home pose.",
            "type": "string",
            "default": ""
          },
          "restarts": {
            "title": "Random restarts",
            "type": "integer",
            "minimum": 0,
            "maximum": 64,
            "default": 12
          },
          "rngSeed": {
            "title": "Random seed",
            "description": "Seeds the deterministic restart generator, so the same input always gives the same solutions.",
            "type": "integer",
            "minimum": 0,
            "maximum": 2147483647,
            "default": 7
          }
        },
        "required": [
          "x",
          "y",
          "z"
        ]
      },
      "KineticaInverseKinematicsResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "required": [
              "ok",
              "solutions",
              "reach",
              "message",
              "task"
            ],
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "message": {
                "type": "string"
              },
              "task": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "best": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "solutions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "joints": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      }
                    },
                    "posError": {
                      "type": "number"
                    },
                    "rotErrorDeg": {
                      "type": "number"
                    },
                    "withinLimits": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string"
                    },
                    "manipulability": {
                      "type": "number"
                    },
                    "source": {
                      "type": "string"
                    }
                  }
                }
              },
              "roundTrip": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "reach": {
                "type": "object",
                "properties": {
                  "distance": {
                    "type": "number"
                  },
                  "maxReach": {
                    "type": "number"
                  },
                  "inReach": {
                    "type": "boolean"
                  }
                }
              },
              "closest": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "attempts": {
                "type": "integer"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "KineticaTrajectoryPlannerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "robot": {
            "title": "Robot",
            "description": "A library robot, or choose a custom DH table, URDF or Kinetica robot JSON.",
            "type": "string",
            "enum": [
              "kx6-1400",
              "ur5-like",
              "puma560",
              "scara-550",
              "gantry-xyz",
              "planar2",
              "custom-dh",
              "urdf",
              "json"
            ],
            "default": "kx6-1400"
          },
          "convention": {
            "title": "DH convention (custom table)",
            "type": "string",
            "enum": [
              "dh",
              "mdh"
            ],
            "default": "dh"
          },
          "dh": {
            "title": "DH table (custom)",
            "description": "One row per joint. Lengths in mm, angles in degrees. For revolute joints θ is the zero offset, for prismatic joints d is.",
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "revolute",
                    "prismatic"
                  ],
                  "default": "revolute"
                },
                "a": {
                  "title": "a (mm)",
                  "type": "number",
                  "default": 0
                },
                "alpha": {
                  "title": "α (deg)",
                  "type": "number",
                  "default": 0
                },
                "d": {
                  "title": "d (mm)",
                  "type": "number",
                  "default": 0
                },
                "theta": {
                  "title": "θ (deg)",
                  "type": "number",
                  "default": 0
                },
                "min": {
                  "title": "min",
                  "type": "number"
                },
                "max": {
                  "title": "max",
                  "type": "number"
                },
                "vmax": {
                  "title": "v max (/s)",
                  "type": "number"
                },
                "amax": {
                  "title": "a max (/s²)",
                  "type": "number"
                }
              },
              "required": []
            }
          },
          "robotText": {
            "title": "URDF or robot JSON",
            "description": "Used when Robot is “URDF” or “Kinetica robot JSON”. URDF subset: links with box/cylinder/sphere, revolute/continuous/prismatic/fixed joints.",
            "type": "string",
            "maxLength": 400000
          },
          "tool": {
            "title": "Tool offset (TCP)",
            "description": "x, y, z (mm), roll, pitch, yaw (deg) in the flange frame, e.g. “0, 0, 150, 0, 0, 0”. Empty = robot default.",
            "type": "string",
            "default": ""
          },
          "waypoints": {
            "title": "Waypoints",
            "description": "Row 1 is the start. Target “j: 0, -90, 90, 0, 0, 0” (joints) or “p: x, y, z, roll, pitch, yaw” (TCP pose, mm/deg). PTP speed/accel in % of the joint limits; LIN/CIRC in mm/s and mm/s². CIRC needs a via point “x, y, z”.",
            "type": "array",
            "maxItems": 60,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Name",
                  "type": "string",
                  "maxLength": 40
                },
                "type": {
                  "title": "Move",
                  "type": "string",
                  "enum": [
                    "PTP",
                    "LIN",
                    "CIRC"
                  ],
                  "default": "PTP"
                },
                "target": {
                  "title": "Target",
                  "type": "string",
                  "maxLength": 200
                },
                "via": {
                  "title": "Via (CIRC)",
                  "type": "string",
                  "maxLength": 100
                },
                "vel": {
                  "title": "Speed",
                  "type": "number",
                  "minimum": 0.01
                },
                "acc": {
                  "title": "Accel",
                  "type": "number",
                  "minimum": 0.01
                },
                "blend": {
                  "title": "Blend (mm)",
                  "type": "number",
                  "minimum": 0,
                  "default": 0
                },
                "dwell": {
                  "title": "Dwell (s)",
                  "type": "number",
                  "minimum": 0,
                  "default": 0
                }
              },
              "required": [
                "target"
              ]
            }
          },
          "projectJson": {
            "title": "Kinetica project JSON (optional)",
            "description": "A complete .kinetica.json project; when given, its robot, work objects and program are used instead of the fields above.",
            "type": "string",
            "maxLength": 1000000
          },
          "profile": {
            "title": "Velocity profile",
            "type": "string",
            "enum": [
              "trapezoid",
              "quintic",
              "scurve"
            ],
            "default": "trapezoid"
          },
          "override": {
            "title": "Speed override",
            "type": "number",
            "minimum": 1,
            "maximum": 100,
            "default": 100,
            "x-unit": "%"
          },
          "outputDt": {
            "title": "Output sample period",
            "type": "number",
            "minimum": 0.005,
            "maximum": 1,
            "default": 0.05,
            "x-unit": "s"
          }
        },
        "required": []
      },
      "KineticaTrajectoryPlannerResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "required": [
              "ok",
              "cycleTime",
              "segments",
              "peaks",
              "samples",
              "joints"
            ],
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "cycleTime": {
                "type": "number"
              },
              "pathLength": {
                "type": "number"
              },
              "joints": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "segments": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "start": {
                      "type": "number"
                    },
                    "duration": {
                      "type": "number"
                    },
                    "blendOverlap": {
                      "type": "number"
                    },
                    "dwell": {
                      "type": "number"
                    },
                    "speedScale": {
                      "type": "number"
                    }
                  }
                }
              },
              "peaks": {
                "type": "object",
                "properties": {
                  "jointVel": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "jointAcc": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "jointVelPercent": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "tcpSpeed": {
                    "type": "number"
                  }
                }
              },
              "samples": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "t": {
                      "type": "number"
                    },
                    "joints": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      }
                    },
                    "tcp": {
                      "type": "array",
                      "items": {
                        "type": "number"
                      }
                    }
                  }
                }
              },
              "errors": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "KineticaCollisionCheckInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "robot": {
            "title": "Robot",
            "description": "A library robot, or choose a custom DH table, URDF or Kinetica robot JSON.",
            "type": "string",
            "enum": [
              "kx6-1400",
              "ur5-like",
              "puma560",
              "scara-550",
              "gantry-xyz",
              "planar2",
              "custom-dh",
              "urdf",
              "json"
            ],
            "default": "kx6-1400"
          },
          "convention": {
            "title": "DH convention (custom table)",
            "type": "string",
            "enum": [
              "dh",
              "mdh"
            ],
            "default": "dh"
          },
          "dh": {
            "title": "DH table (custom)",
            "description": "One row per joint. Lengths in mm, angles in degrees. For revolute joints θ is the zero offset, for prismatic joints d is.",
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "type": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "revolute",
                    "prismatic"
                  ],
                  "default": "revolute"
                },
                "a": {
                  "title": "a (mm)",
                  "type": "number",
                  "default": 0
                },
                "alpha": {
                  "title": "α (deg)",
                  "type": "number",
                  "default": 0
                },
                "d": {
                  "title": "d (mm)",
                  "type": "number",
                  "default": 0
                },
                "theta": {
                  "title": "θ (deg)",
                  "type": "number",
                  "default": 0
                },
                "min": {
                  "title": "min",
                  "type": "number"
                },
                "max": {
                  "title": "max",
                  "type": "number"
                },
                "vmax": {
                  "title": "v max (/s)",
                  "type": "number"
                },
                "amax": {
                  "title": "a max (/s²)",
                  "type": "number"
                }
              },
              "required": []
            }
          },
          "robotText": {
            "title": "URDF or robot JSON",
            "description": "Used when Robot is “URDF” or “Kinetica robot JSON”. URDF subset: links with box/cylinder/sphere, revolute/continuous/prismatic/fixed joints.",
            "type": "string",
            "maxLength": 400000
          },
          "tool": {
            "title": "Tool offset (TCP)",
            "description": "x, y, z (mm), roll, pitch, yaw (deg) in the flange frame, e.g. “0, 0, 150, 0, 0, 0”. Empty = robot default.",
            "type": "string",
            "default": ""
          },
          "joints": {
            "title": "Joint values",
            "description": "Degrees / mm. Empty = home pose.",
            "type": "string",
            "default": ""
          },
          "obstacles": {
            "title": "Obstacles",
            "description": "Box: centre x, y, z and size sx, sy, sz. Sphere: centre and r. Capsule: start x, y, z, end x2, y2, z2 (in the size columns) and r. All in mm, world frame.",
            "type": "array",
            "maxItems": 50,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Name",
                  "type": "string",
                  "maxLength": 40
                },
                "shape": {
                  "title": "Shape",
                  "type": "string",
                  "enum": [
                    "box",
                    "sphere",
                    "capsule"
                  ],
                  "default": "box"
                },
                "x": {
                  "title": "x",
                  "type": "number"
                },
                "y": {
                  "title": "y",
                  "type": "number"
                },
                "z": {
                  "title": "z",
                  "type": "number"
                },
                "sx": {
                  "title": "sx / x2",
                  "type": "number"
                },
                "sy": {
                  "title": "sy / y2",
                  "type": "number"
                },
                "sz": {
                  "title": "sz / z2",
                  "type": "number"
                },
                "r": {
                  "title": "r",
                  "type": "number",
                  "minimum": 0
                }
              },
              "required": [
                "x",
                "y",
                "z"
              ]
            }
          },
          "self": {
            "title": "Check self-collision",
            "type": "boolean",
            "default": true
          },
          "margin": {
            "title": "Safety margin",
            "type": "number",
            "minimum": 0,
            "maximum": 1000,
            "default": 10,
            "x-unit": "mm"
          }
        },
        "required": []
      },
      "KineticaCollisionCheckResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "required": [
              "collides",
              "minClearance",
              "contacts",
              "links",
              "checkedPairs"
            ],
            "properties": {
              "collides": {
                "type": "boolean"
              },
              "minClearance": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "closest": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "contacts": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "a": {
                      "type": "string"
                    },
                    "b": {
                      "type": "string"
                    },
                    "distance": {
                      "type": "number"
                    },
                    "kind": {
                      "type": "string"
                    }
                  }
                }
              },
              "links": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "checkedPairs": {
                "type": "integer"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}