Skip to content

Changes

Propose a change for review

Propose a change to an authorized event and get back a reviewable plan: a title, a labeled before and after for every field that moves, what applying it would affect, and reviewUrl, the full link where a person approves it. Use this for any change no dedicated tool covers (speakers and panelists, FAQ, links, pages, schedule items, lottery settings, runner requirements, registration questions, add-ons, volunteer roles, automations and more): find the procedure path with capability discovery and pass that procedure's own input. For a whole registration ruleset described in prose, ehq_registration_rules_propose files one plan for every section instead. Nothing is saved by this call. Show the user the before and after values; once they want it made, call ehq_changes_apply with the planId. If apply returns APPROVAL_REQUIRED and the user explicitly approves the reviewed plan here, inspect it and use ehq_changes_approve when this personal OAuth connection has changes:approve. Otherwise use its reviewUrl. Send an Idempotency-Key header.

Method

POST

Path

/v1/changes/prepare

Required scope

changes:propose

Request

curl -X POST "https://api.endurancehq.app/v1/changes/prepare" \
  -H "Authorization: Bearer $EHQ_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

JSON body schema

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "path": {
      "type": "string",
      "minLength": 1,
      "maxLength": 300,
      "description": "Procedure path of the change to propose, for example raceDay.createScheduleItem or speakers.update. Use capability discovery to find the exact path."
    },
    "input": {
      "description": "The change's own input, validated against that procedure's schema before any plan is written.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    },
    "eventId": {
      "description": "Which event this change belongs to. Always pass it when the input addresses a record by id (a speaker, schedule item or FAQ): without it the plan has no before-and-after and always waits for review. Access is still decided by the user's own permissions.",
      "type": "string",
      "minLength": 1,
      "maxLength": 200
    }
  },
  "required": [
    "path"
  ],
  "additionalProperties": false
}

Response

Success status: 201

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "data": {
      "type": "object",
      "properties": {
        "planId": {
          "type": "string"
        },
        "title": {
          "type": "string"
        },
        "summary": {
          "type": "string"
        },
        "risk": {
          "type": "string",
          "enum": [
            "low",
            "medium",
            "high"
          ]
        },
        "fidelity": {
          "type": "string",
          "enum": [
            "kind_module",
            "raw_input"
          ]
        },
        "diff": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "field": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "label": {
                "type": "string"
              },
              "before": {},
              "after": {},
              "beforeText": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "afterText": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "field",
              "label",
              "before",
              "after",
              "beforeText",
              "afterText"
            ],
            "additionalProperties": false
          }
        },
        "effects": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "reviewHref": {
          "type": "string"
        },
        "reviewUrl": {
          "type": "string"
        },
        "expiresAt": {
          "type": "string",
          "format": "date-time",
          "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
        }
      },
      "required": [
        "planId",
        "title",
        "summary",
        "risk",
        "fidelity",
        "diff",
        "effects",
        "reviewHref",
        "reviewUrl",
        "expiresAt"
      ],
      "additionalProperties": false
    }
  },
  "required": [
    "data"
  ],
  "additionalProperties": false
}

Other surfaces

CLI: ehq changes propose <procedure_path> --input <json> [--event <event_id>]

MCP tool: ehq_changes_propose