{
  "components": {
    "schemas": {
      "AgentApplyTextStyleRequest": {
        "type": "object",
        "properties": {
          "payload": {
            "description": "ApplyTextStyle payload",
            "type": "object",
            "properties": {
              "all_text": {
                "description": "Apply style to entire flattened text when true",
                "type": "boolean"
              },
              "portion_style": {
                "description": "Optional portion style patch",
                "type": "object",
                "properties": {
                  "fontweight": {
                    "description": "Optional font weight token",
                    "type": "string",
                    "maxLength": 100,
                    "enum": [
                      "THIN",
                      "EXTRA_LIGHT",
                      "LIGHT",
                      "NORMAL",
                      "MEDIUM",
                      "DEMI_BOLD",
                      "BOLD",
                      "HEAVY",
                      "BLACK"
                    ]
                  },
                  "size": {
                    "description": "Optional portion font size",
                    "type": "number"
                  },
                  "color": {
                    "description": "Optional text color patch",
                    "type": "object",
                    "properties": {
                      "hsb": {
                        "description": "HSB color value",
                        "type": "object",
                        "properties": {
                          "saturation": {
                            "description": "Saturation 0-1",
                            "type": "number"
                          },
                          "brightness": {
                            "description": "Brightness 0-1",
                            "type": "number"
                          },
                          "hue": {
                            "description": "Hue in degrees",
                            "type": "number"
                          }
                        }
                      },
                      "hex": {
                        "description": "Hex color value",
                        "type": "object",
                        "properties": {
                          "value": {
                            "pattern": "^#?[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$",
                            "description": "Hex color literal such as #8B4513",
                            "type": "string",
                            "maxLength": 50
                          }
                        }
                      },
                      "rgb": {
                        "description": "RGB color value",
                        "type": "object",
                        "properties": {
                          "red": {
                            "description": "Red channel 0-255",
                            "type": "integer"
                          },
                          "green": {
                            "description": "Green channel 0-255",
                            "type": "integer"
                          },
                          "blue": {
                            "description": "Blue channel 0-255",
                            "type": "integer"
                          }
                        }
                      }
                    }
                  },
                  "underline": {
                    "description": "Optional underline toggle",
                    "type": "boolean"
                  },
                  "strike": {
                    "description": "Optional strike toggle",
                    "type": "boolean"
                  },
                  "italic": {
                    "description": "Optional italic toggle",
                    "type": "boolean"
                  },
                  "font_name": {
                    "description": "Optional font family/style patch",
                    "type": "object",
                    "properties": {
                      "name": {
                        "pattern": "^(?:[0-9a-zA-Z_~`#%&\\^\\*\\(\\)\\{\\}\\[\\]\\+\\*\\|=\\-\\.\\$@\\?,:;>\\\\'\\/!\\u0080-\\uFFFF\\s<\"]+)$",
                        "description": "Font display name",
                        "type": "string",
                        "maxLength": 500
                      },
                      "style": {
                        "pattern": "^(?:[A-Za-z_0-9- ]+)$",
                        "description": "Optional font style token",
                        "type": "string",
                        "maxLength": 200
                      }
                    }
                  }
                }
              },
              "range": {
                "description": "Apply style within selected range",
                "type": "object",
                "properties": {
                  "start_index": {
                    "description": "Inclusive start index on flattened text (>= 0)",
                    "type": "integer"
                  },
                  "end_index": {
                    "description": "Exclusive end index on flattened text (> start_index)",
                    "type": "integer"
                  }
                },
                "required": [
                  "start_index",
                  "end_index"
                ]
              },
              "paragraph_style": {
                "description": "Optional paragraph style patch",
                "type": "object",
                "properties": {
                  "spacing": {
                    "description": "Optional paragraph spacing patch",
                    "type": "object",
                    "properties": {
                      "before": {
                        "description": "Optional space before paragraph, in points (>= 0)",
                        "type": "integer"
                      },
                      "line": {
                        "description": "Optional line-height multiplier (e.g. 1.5 = 150%)",
                        "type": "number"
                      },
                      "after": {
                        "description": "Optional space after paragraph, in points (>= 0)",
                        "type": "integer"
                      }
                    }
                  },
                  "level": {
                    "description": "Optional paragraph level",
                    "type": "integer"
                  },
                  "halign": {
                    "description": "Optional paragraph alignment token",
                    "type": "string",
                    "maxLength": 50,
                    "enum": [
                      "LEFT",
                      "CENTER",
                      "RIGHT",
                      "JUSTIFY"
                    ]
                  }
                }
              }
            }
          },
          "object": {
            "description": "Target text-bearing object",
            "type": "object",
            "properties": {
              "zone_id": {
                "pattern": "^[a-f0-9A-F]{8}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{12}$",
                "description": "Zone containing the object",
                "type": "string",
                "maxLength": 200
              },
              "object_id": {
                "pattern": "^[a-f0-9A-F]{8}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{12}$",
                "description": "Object id in the frame",
                "type": "string",
                "maxLength": 200
              },
              "frame_id": {
                "pattern": "^[a-f0-9A-F]{8}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{12}$",
                "description": "Frame containing the object",
                "type": "string",
                "maxLength": 200
              }
            }
          }
        },
        "required": [
          "object",
          "payload"
        ]
      },
      "AgentError": {
        "type": "object",
        "properties": {
          "code": {
            "$ref": "#/components/schemas/AgentErrorCode"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "AgentEditTextRequest": {
        "type": "object",
        "properties": {
          "payload": {
            "description": "EditText payload",
            "type": "object",
            "properties": {
              "cursor": {
                "description": "Cursor-scoped insert/delete mutation",
                "type": "object",
                "properties": {
                  "cursor_index": {
                    "description": "Cursor index on flattened text",
                    "type": "integer"
                  },
                  "text": {
                    "pattern": "^[0-9a-zA-Z_~`#%&\\^\\*\\(\\)\\{\\}\\[\\]\\+\\*\\|=\\-\\.\\$@\\?,:;>\\\\'\\/!\\u0080-\\uFFFF\\s<\"]*$",
                    "description": "Text to insert (required when operation=CURSOR_TEXT_OPERATION_INSERT_TEXT)",
                    "type": "string",
                    "maxLength": 500000
                  },
                  "operation": {
                    "description": "Cursor mutation operation",
                    "type": "string",
                    "maxLength": 50,
                    "enum": [
                      "CURSOR_TEXT_OPERATION_UNSPECIFIED",
                      "CURSOR_TEXT_OPERATION_INSERT_TEXT",
                      "CURSOR_TEXT_OPERATION_INSERT_NEWLINE",
                      "CURSOR_TEXT_OPERATION_DELETE_NEWLINE"
                    ]
                  }
                },
                "required": [
                  "cursor_index",
                  "operation"
                ]
              },
              "all_text": {
                "description": "Full-text replace/delete mutation",
                "type": "object",
                "properties": {
                  "replacement_text": {
                    "pattern": "^[0-9a-zA-Z_~`#%&\\^\\*\\(\\)\\{\\}\\[\\]\\+\\*\\|=\\-\\.\\$@\\?,:;>\\\\'\\/!\\u0080-\\uFFFF\\s<\"]*$",
                    "description": "Replacement text (required when operation=ALL_TEXT_OPERATION_REPLACE)",
                    "type": "string",
                    "maxLength": 500000
                  },
                  "operation": {
                    "description": "Full-text mutation operation",
                    "type": "string",
                    "maxLength": 50,
                    "enum": [
                      "ALL_TEXT_OPERATION_UNSPECIFIED",
                      "ALL_TEXT_OPERATION_REPLACE",
                      "ALL_TEXT_OPERATION_DELETE"
                    ]
                  }
                },
                "required": [
                  "operation"
                ]
              },
              "range": {
                "description": "Range-scoped replace/delete mutation",
                "type": "object",
                "properties": {
                  "replacement_text": {
                    "pattern": "^[0-9a-zA-Z_~`#%&\\^\\*\\(\\)\\{\\}\\[\\]\\+\\*\\|=\\-\\.\\$@\\?,:;>\\\\'\\/!\\u0080-\\uFFFF\\s<\"]*$",
                    "description": "Replacement text (required when operation=RANGE_TEXT_OPERATION_REPLACE)",
                    "type": "string",
                    "maxLength": 500000
                  },
                  "range": {
                    "description": "Target range in flattened text",
                    "type": "object",
                    "properties": {
                      "start_index": {
                        "description": "Inclusive start index on flattened text (>= 0)",
                        "type": "integer"
                      },
                      "end_index": {
                        "description": "Exclusive end index on flattened text (> start_index)",
                        "type": "integer"
                      }
                    },
                    "required": [
                      "start_index",
                      "end_index"
                    ]
                  },
                  "operation": {
                    "description": "Range mutation operation",
                    "type": "string",
                    "maxLength": 50,
                    "enum": [
                      "RANGE_TEXT_OPERATION_UNSPECIFIED",
                      "RANGE_TEXT_OPERATION_REPLACE",
                      "RANGE_TEXT_OPERATION_DELETE"
                    ]
                  }
                },
                "required": [
                  "range",
                  "operation"
                ]
              }
            }
          },
          "object": {
            "description": "Target text-bearing object",
            "type": "object",
            "properties": {
              "zone_id": {
                "pattern": "^[a-f0-9A-F]{8}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{12}$",
                "description": "Zone containing the object",
                "type": "string",
                "maxLength": 200
              },
              "object_id": {
                "pattern": "^[a-f0-9A-F]{8}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{12}$",
                "description": "Object id in the frame",
                "type": "string",
                "maxLength": 200
              },
              "frame_id": {
                "pattern": "^[a-f0-9A-F]{8}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{4}-[a-f0-9A-F]{12}$",
                "description": "Frame containing the object",
                "type": "string",
                "maxLength": 200
              }
            }
          }
        },
        "required": [
          "object",
          "payload"
        ]
      },
      "MutationMetadata": {
        "type": "object",
        "properties": {
          "new_revision_id": {
            "type": "string"
          }
        }
      },
      "VaniEnvelope": {
        "description": "Standard Vani response envelope.",
        "type": "object",
        "properties": {
          "data": {
            "description": "Operation payload. Narrowed per endpoint where a response schema is declared.",
            "type": "object"
          },
          "message": {
            "type": "string"
          },
          "request_uri": {
            "type": "string"
          },
          "status": {
            "description": "success or error",
            "type": "string"
          }
        },
        "required": [
          "status"
        ]
      },
      "AgentErrorCode": {
        "type": "string",
        "enum": [
          "AGENT_ERROR_CODE_UNSPECIFIED",
          "INVALID_ARGUMENT",
          "SPACE_NOT_FOUND",
          "ZONE_NOT_FOUND",
          "FRAME_NOT_FOUND",
          "OBJECT_NOT_FOUND",
          "NO_EMPTY_REGION",
          "NO_VISUAL_NEIGHBOR",
          "PLACEMENT_CONFLICT",
          "UNSUPPORTED_OPERATION",
          "INTERNAL_ERROR"
        ]
      },
      "VaniError": {
        "description": "Standard Vani error envelope.",
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "details": {
                "description": "Error code and message, plus any context keys (edition_id, space_id, ...).",
                "additionalProperties": true,
                "type": "object",
                "properties": {
                  "sdk_error_code": {
                    "description": "Raw SDK code, present when the error was not mapped.",
                    "type": "string"
                  },
                  "error_code": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "request_uri": {
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        }
      },
      "TextRange": {
        "type": "object",
        "properties": {
          "start_index": {
            "format": "int32",
            "type": "string"
          },
          "end_index": {
            "format": "int32",
            "type": "string"
          }
        }
      },
      "EditTextResult": {
        "type": "object",
        "properties": {
          "applied_range": {
            "$ref": "#/components/schemas/TextRange"
          }
        }
      },
      "ApplyTextStyleResponse": {
        "type": "object",
        "properties": {
          "result": {
            "$ref": "#/components/schemas/ApplyTextStyleResult"
          },
          "mutation": {
            "$ref": "#/components/schemas/MutationMetadata"
          },
          "error": {
            "$ref": "#/components/schemas/AgentError"
          },
          "object": {
            "$ref": "#/components/schemas/ObjectRef"
          }
        }
      },
      "ApplyTextStyleResult": {
        "type": "object",
        "properties": {
          "affected_paragraph_count": {
            "format": "int32",
            "type": "string"
          },
          "affected_portion_count": {
            "format": "int32",
            "type": "string"
          }
        }
      },
      "EditTextResponse": {
        "type": "object",
        "properties": {
          "result": {
            "$ref": "#/components/schemas/EditTextResult"
          },
          "mutation": {
            "$ref": "#/components/schemas/MutationMetadata"
          },
          "error": {
            "$ref": "#/components/schemas/AgentError"
          },
          "object": {
            "$ref": "#/components/schemas/ObjectRef"
          }
        }
      },
      "ObjectRef": {
        "type": "object",
        "properties": {
          "zone_id": {
            "type": "string"
          },
          "object_id": {
            "type": "string"
          },
          "frame_id": {
            "type": "string"
          }
        }
      }
    },
    "responses": {
      "InvalidRequestValidationFailed": {
        "description": "Invalid request - validation failed",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/VaniError"
            }
          }
        }
      },
      "RateLimitExceededThisOperationAllows60Re": {
        "description": "Rate limit exceeded - this operation allows 60 requests per minute per user",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/VaniError"
            }
          }
        }
      },
      "NotFoundAResourceNamedInThePathDoesNotEx10": {
        "description": "Not found - a resource named in the path does not exist, or is not visible to the caller",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/VaniError"
            }
          }
        }
      },
      "InternalServerErrorTheRequestWasWellForm": {
        "description": "Internal server error - the request was well-formed but could not be completed",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/VaniError"
            }
          }
        }
      },
      "UnauthorizedMissingOrInvalidAccessToken9": {
        "description": "Unauthorized - missing or invalid access token",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/VaniError"
            }
          }
        }
      }
    },
    "securitySchemes": {
      "vani-api-key": {
        "in": "header",
        "name": "x-vani-apikey",
        "description": "Edition-scoped API key. ACCEPTED, NOT YET REQUIRED: the bearer token alone authorises every operation today, which is why each one lists a token-only alternative first and a token-plus-key alternative second. Sending the key is harmless and forward-compatible -- the server reads it, and the requirement is expected to become mandatory, at which point the token-only alternative disappears from this contract. The key never authorises on its own. Read or create your edition's key from the edition settings. The two operations on the /editions collection itself never carry one: a key belongs to an edition, so the calls that list or create editions cannot present it.",
        "type": "apiKey"
      },
      "iam-oauth2-schema": {
        "flows": {
          "authorizationCode": {
            "tokenUrl": "https://accounts.zoho.com/oauth/v2/token",
            "authorizationUrl": "https://accounts.zoho.com/oauth/v2/auth",
            "scopes": {
              "Vani.teams.UPDATE": "Update team memberships, roles, and collaboration settings",
              "Vani.spaces.UPDATE": "Update workspaces, folders, and organizational settings",
              "Vani.spaces.DELETE": "Delete workspaces and folders",
              "Vani.zones.READ": "Read zones including tables, cells, and paragraph content",
              "Vani.editions.UPDATE": "Update existing document editions, modify version metadata and publishing state",
              "Vani.spaces.CREATE": "Create new workspaces, folders, and organizational structure",
              "Vani.teams.CREATE": "Create new teams and assign team memberships",
              "Vani.spaces.READ": "Read workspaces, folders, and organizational structure",
              "Vani.editions.CREATE": "Create new document editions and version snapshots",
              "Vani.zones.CREATE": "Create zones including tables, cells, and paragraph content",
              "Vani.teams.READ": "Read team memberships, roles, and collaboration settings",
              "Vani.editions.READ": "Read document editions, version history, and edition metadata",
              "Vani.teams.DELETE": "Delete teams and remove team memberships"
            }
          }
        },
        "x-vani-data-centre": "com",
        "description": "OAuth 2.0 through Zoho Accounts for the .com data centre (the default). Authorisation is NOT served by the API server -- it is a separate host, and each data centre has its own. If your edition is on another data centre, keep these paths and substitute its host from x-vani-accounts-hosts on this scheme. An OAuth client is valid only in the data centre it was registered in, so register at that data centre's api-console. Note that the accounts host does not simply mirror the API host's TLD: Canada authorises at accounts.zohocloud.ca.",
        "x-vani-accounts-hosts": {
          "com": "accounts.zoho.com",
          "eu": "accounts.zoho.eu",
          "ae": "accounts.zoho.ae",
          "in": "accounts.zoho.in",
          "ca": "accounts.zohocloud.ca",
          "sa": "accounts.zoho.sa",
          "com.au": "accounts.zoho.com.au"
        },
        "type": "oauth2"
      }
    },
    "parameters": {
      "ZoneId": {
        "schema": {
          "type": "string"
        },
        "in": "path",
        "name": "zone_id",
        "description": "The unique identifier of the zone",
        "required": true
      },
      "SpaceId": {
        "schema": {
          "type": "string"
        },
        "in": "path",
        "name": "space_id",
        "description": "The unique identifier of the space",
        "required": true
      },
      "EditionId": {
        "schema": {
          "type": "string"
        },
        "in": "path",
        "name": "edition_id",
        "description": "The unique identifier of the edition",
        "required": true
      }
    }
  },
  "servers": [
    {
      "variables": {
        "dc": {
          "default": "com",
          "description": "Data-centre TLD for your edition.",
          "enum": [
            "com",
            "in",
            "eu",
            "ca",
            "com.au",
            "sa",
            "ae"
          ]
        }
      },
      "description": "Vani API server. Select the data centre your edition is hosted in.",
      "url": "https://api.app.vanihq.{dc}"
    }
  ],
  "openapi": "3.1.0",
  "paths": {
    "/sdk/v1/editions/{edition_id}/spaces/{space_id}/zones/{zone_id}/text/edit": {
      "post": {
        "summary": "Canonical text mutation API for replace/insert/delete/split/merge operations",
        "security": [
          {
            "iam-oauth2-schema": [
              "Vani.spaces.CREATE"
            ]
          },
          {
            "vani-api-key": [],
            "iam-oauth2-schema": [
              "Vani.spaces.CREATE"
            ]
          }
        ],
        "x-vani-transitional": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentEditTextRequest"
              }
            }
          }
        },
        "operationId": "editText",
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/VaniEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/EditTextResponse"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequestValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedMissingOrInvalidAccessToken9"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundAResourceNamedInThePathDoesNotEx10"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceededThisOperationAllows60Re"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorTheRequestWasWellForm"
          }
        },
        "x-vani-operation-type": "CREATE",
        "parameters": [
          {
            "$ref": "#/components/parameters/EditionId"
          },
          {
            "$ref": "#/components/parameters/SpaceId"
          },
          {
            "$ref": "#/components/parameters/ZoneId"
          }
        ],
        "x-vani-read-only": false,
        "x-vani-destructive": false,
        "x-vani-throttle": {
          "duration": "1M",
          "threshold": 60
        },
        "tags": [
          "Text"
        ]
      }
    },
    "/sdk/v1/editions/{edition_id}/spaces/{space_id}/zones/{zone_id}/text/style": {
      "post": {
        "summary": "Apply portion and or paragraph style to selected text scope",
        "security": [
          {
            "iam-oauth2-schema": [
              "Vani.spaces.CREATE"
            ]
          },
          {
            "vani-api-key": [],
            "iam-oauth2-schema": [
              "Vani.spaces.CREATE"
            ]
          }
        ],
        "x-vani-transitional": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AgentApplyTextStyleRequest"
              }
            }
          }
        },
        "operationId": "applyTextStyle",
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/VaniEnvelope"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "data": {
                          "$ref": "#/components/schemas/ApplyTextStyleResponse"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequestValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedMissingOrInvalidAccessToken9"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundAResourceNamedInThePathDoesNotEx10"
          },
          "429": {
            "$ref": "#/components/responses/RateLimitExceededThisOperationAllows60Re"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerErrorTheRequestWasWellForm"
          }
        },
        "x-vani-operation-type": "CREATE",
        "parameters": [
          {
            "$ref": "#/components/parameters/EditionId"
          },
          {
            "$ref": "#/components/parameters/SpaceId"
          },
          {
            "$ref": "#/components/parameters/ZoneId"
          }
        ],
        "x-vani-read-only": false,
        "x-vani-destructive": false,
        "x-vani-throttle": {
          "duration": "1M",
          "threshold": 60
        },
        "tags": [
          "Text"
        ]
      }
    }
  },
  "info": {
    "contact": {
      "name": "Vani API Support",
      "url": "https://www.vanihq.com/resources/api/doc/"
    },
    "description": "Read and mutate text on any text-bearing object, including styling.",
    "title": "Text",
    "version": "1.0.0"
  },
  "tags": [
    {
      "name": "Text",
      "description": "Mutate and style text on any text-bearing object."
    }
  ]
}