{
  "openapi": "3.1.0",
  "info": {
    "title": "Envoke Tag API",
    "version": "2.0.0",
    "description": "Full CRUD API for managing tags (interests) and their contact assignments. All endpoints require HTTP Basic Auth and return JSON. Tags are hard-deleted — deletion permanently removes the tag and all contact associations."
  },
  "servers": [
    {
      "url": "https://e1.envoke.com/v2",
      "description": "Production"
    }
  ],
  "security": [
    {
      "basicAuth": []
    }
  ],
  "tags": [
    {
      "name": "Tags",
      "description": "Operations on tags."
    },
    {
      "name": "Tag Contacts",
      "description": "Bulk add and remove contacts from a tag."
    }
  ],
  "components": {
    "securitySchemes": {
      "basicAuth": {
        "type": "http",
        "scheme": "basic",
        "description": "HTTP Basic Auth. Use your API ID as the username and API Key as the password."
      }
    },
    "schemas": {
      "Tag": {
        "type": "object",
        "description": "A tag (interest) definition.",
        "required": [
          "id",
          "external_id",
          "name",
          "group",
          "description",
          "display_names"
        ],
        "properties": {
          "id": {
            "type": "string",
            "readOnly": true,
            "description": "Unique identifier assigned on creation. Returned as a string.",
            "examples": [
              "42"
            ]
          },
          "external_id": {
            "type": "string",
            "readOnly": true,
            "description": "Externally visible identifier used in public-facing integrations.",
            "examples": [
              "a1b2c3d4e5f6"
            ]
          },
          "name": {
            "type": "string",
            "description": "The tag name.",
            "examples": [
              "Newsletter Subscribers"
            ]
          },
          "group": {
            "type": "string",
            "description": "Name of the group the tag belongs to. Empty string (`\"\"`) when no group is assigned.",
            "examples": [
              "Member Programs",
              ""
            ]
          },
          "description": {
            "type": "string",
            "description": "Internal description of the tag. Not visible to contacts. Empty string when not set.",
            "examples": [
              "Members interested in the annual conference"
            ]
          },
          "display_names": {
            "type": "object",
            "description": "Translated display labels keyed by ISO language code. Used in public-facing contexts such as website forms. Values are empty strings when no translation is set.",
            "additionalProperties": {
              "type": "string"
            },
            "examples": [
              {
                "en": "Newsletter",
                "fr": "Infolettre"
              }
            ]
          }
        }
      },
      "TagCreate": {
        "type": "object",
        "description": "Request body for creating a new tag. `name` is required.",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "The tag name.",
            "examples": [
              "Newsletter Subscribers"
            ]
          },
          "group": {
            "type": [
              "string",
              "integer"
            ],
            "description": "Group to assign the tag to. Accepts the group name (string) or group ID (integer). The group must be of type `interest`.",
            "examples": [
              "Member Programs",
              5
            ]
          },
          "description": {
            "type": "string",
            "description": "Internal description of the tag.",
            "examples": [
              "Members interested in the annual conference"
            ]
          },
          "display_names": {
            "type": "object",
            "description": "Translated display labels keyed by ISO language code.",
            "additionalProperties": {
              "type": "string"
            },
            "examples": [
              {
                "en": "Newsletter",
                "fr": "Infolettre"
              }
            ]
          }
        }
      },
      "TagUpdate": {
        "type": "object",
        "description": "Request body for updating a tag. At least one field must be provided. `external_id` is silently ignored if included. If `id` is included, it must match the `{id}` in the URL.",
        "minProperties": 1,
        "properties": {
          "id": {
            "type": [
              "integer",
              "string"
            ],
            "description": "Optional. If provided, must match the `{id}` in the URL. A mismatch returns a validation envelope.",
            "examples": [
              42
            ]
          },
          "name": {
            "type": "string",
            "description": "New name for the tag.",
            "examples": [
              "Updated Tag Name"
            ]
          },
          "group": {
            "type": [
              "string",
              "integer"
            ],
            "description": "Group to assign the tag to. Accepts group name or group ID. Pass `\"\"` (empty string) to remove the group assignment.",
            "examples": [
              "Certification Programs",
              ""
            ]
          },
          "description": {
            "type": "string",
            "description": "Updated internal description.",
            "examples": [
              "Updated description"
            ]
          },
          "display_names": {
            "type": "object",
            "description": "Translated display labels keyed by ISO language code.",
            "additionalProperties": {
              "type": "string"
            },
            "examples": [
              {
                "en": "Organic",
                "fr": "Biologique"
              }
            ]
          }
        }
      },
      "ContactsRequest": {
        "type": "object",
        "description": "Request body for adding or removing contacts. Provide exactly one of `contact_ids` or `contact_emails`.",
        "oneOf": [
          {
            "required": [
              "contact_ids"
            ],
            "properties": {
              "contact_ids": {
                "type": "array",
                "items": {
                  "type": "integer"
                },
                "minItems": 1,
                "maxItems": 1000,
                "description": "Envoke contact IDs to add or remove.",
                "examples": [
                  [
                    101,
                    102,
                    103
                  ]
                ]
              }
            }
          },
          {
            "required": [
              "contact_emails"
            ],
            "properties": {
              "contact_emails": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "minItems": 1,
                "maxItems": 1000,
                "description": "Contact email addresses to add or remove.",
                "examples": [
                  [
                    "alice@example.com",
                    "bob@example.com"
                  ]
                ]
              }
            }
          }
        ]
      },
      "ContactsSuccessResponse": {
        "type": "object",
        "description": "Returned after a contacts add or remove operation.",
        "required": [
          "success",
          "result_text",
          "result_data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "description": "`true` if no found contacts failed to update. `true` even when some identifiers were not found."
          },
          "result_text": {
            "type": "string",
            "description": "Human-readable summary.",
            "examples": [
              "Set to contacts",
              "Set to contacts. Some contacts not found",
              "Error setting to contacts"
            ]
          },
          "result_data": {
            "type": "object",
            "required": [
              "processed"
            ],
            "properties": {
              "processed": {
                "type": "integer",
                "description": "Total number of input identifiers submitted."
              },
              "not_found": {
                "type": "array",
                "description": "IDs or emails that were not matched to any contact. Only present when at least one was not found.",
                "items": {
                  "type": [
                    "string",
                    "integer"
                  ]
                }
              },
              "failed": {
                "type": "array",
                "description": "Contacts that were found but failed during the update. Only present when failures occurred.",
                "items": {
                  "type": "object",
                  "required": [
                    "contact_id",
                    "reason"
                  ],
                  "properties": {
                    "contact_id": {
                      "type": [
                        "string",
                        "integer"
                      ]
                    },
                    "reason": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "CreateSuccessResponse": {
        "type": "object",
        "description": "Returned on successful tag creation.",
        "required": [
          "success",
          "result_text",
          "result_data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "result_text": {
            "type": "string",
            "const": "Created"
          },
          "result_data": {
            "$ref": "#/components/schemas/Tag"
          }
        }
      },
      "UpdateSuccessResponse": {
        "type": "object",
        "description": "Returned on successful tag update.",
        "required": [
          "success",
          "result_text",
          "result_data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "result_text": {
            "type": "string",
            "const": "Updated"
          },
          "result_data": {
            "$ref": "#/components/schemas/Tag"
          }
        }
      },
      "DeleteSuccessResponse": {
        "type": "object",
        "description": "Returned on successful tag deletion.",
        "required": [
          "success",
          "result_text",
          "result_data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "result_text": {
            "type": "string",
            "const": "Deleted"
          },
          "result_data": {
            "type": "array",
            "maxItems": 0
          }
        }
      },
      "ValidationErrorResponse": {
        "type": "object",
        "description": "Returned when request body or path parameter validation fails.",
        "required": [
          "success",
          "result_text",
          "result_data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "result_text": {
            "type": "string",
            "const": "Validation failed, see 'result_data' -> 'errors'"
          },
          "result_data": {
            "type": "object",
            "required": [
              "errors"
            ],
            "properties": {
              "errors": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "One or more human-readable validation error messages."
              }
            }
          }
        }
      }
    },
    "parameters": {
      "TagId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The unique ID of the tag.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "description": "Maximum number of records to return. Default is 10, hard cap is 100. When used alongside `?fields=` or `?result_type=kvp`, the cap is lifted and an explicit limit above 100 is honoured as-is.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 10
        }
      },
      "Skip": {
        "name": "skip",
        "in": "query",
        "description": "Number of records to skip. Used for pagination.",
        "schema": {
          "type": "integer",
          "minimum": 0,
          "default": 0
        }
      },
      "Fields": {
        "name": "fields",
        "in": "query",
        "description": "Comma-separated list of fields to include in each response object. When set, the default limit increases to 10,000 and the 100-record hard cap is lifted.",
        "schema": {
          "type": "string"
        },
        "example": "id,name,group"
      },
      "ResultType": {
        "name": "result_type",
        "in": "query",
        "description": "Set to `kvp` to receive results as a flat key-value object (`{ \"<id>\": \"<name>\" }`) instead of an array of objects. When set, the default limit increases to 10,000 and the hard cap is lifted.",
        "schema": {
          "type": "string",
          "enum": [
            "kvp"
          ]
        }
      }
    },
    "responses": {
      "NotFoundGet": {
        "description": "The requested tag ID was not found. Returns an empty array.",
        "content": {
          "application/json": {
            "schema": {
              "type": "array",
              "maxItems": 0
            },
            "example": []
          }
        }
      },
      "NotFoundMutate": {
        "description": "The requested tag ID was not found. Returns a validation error envelope.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ValidationErrorResponse"
            },
            "example": {
              "success": false,
              "result_text": "Validation failed, see 'result_data' -> 'errors'",
              "result_data": {
                "errors": [
                  "Item with id '999999' not found"
                ]
              }
            }
          }
        }
      }
    }
  },
  "paths": {
    "/tags": {
      "get": {
        "summary": "List tags",
        "description": "Returns a paginated array of tags for the authenticated account, sorted alphabetically by name by default. Supports filtering by `id`, `name`, `external_id`, `group`, and `description`. Use `?result_type=kvp` for a flat id-to-name map. Filter operators supported: exact match and `(ne)` (not equal).",
        "operationId": "listTags",
        "tags": [
          "Tags"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Skip"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/ResultType"
          },
          {
            "name": "filter[id]",
            "in": "query",
            "description": "Filter by tag ID. Supports `(ne)` operator.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter[name]",
            "in": "query",
            "description": "Filter by tag name. Supports `(ne)` operator.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter[external_id]",
            "in": "query",
            "description": "Filter by external ID. Supports `(ne)` operator.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter[group]",
            "in": "query",
            "description": "Filter by group name. Supports `(ne)` operator.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter[description]",
            "in": "query",
            "description": "Filter by description. Supports `(ne)` operator.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort[name]",
            "in": "query",
            "description": "Sort by name. Value: `asc` or `desc`.",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A list of tags.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Tag"
                      }
                    },
                    {
                      "type": "object",
                      "description": "Key-value map of tag ID to name.",
                      "additionalProperties": {
                        "type": "string"
                      }
                    }
                  ]
                },
                "examples": {
                  "array": {
                    "summary": "Default array response",
                    "value": [
                      {
                        "id": "42",
                        "external_id": "a1b2c3d4e5f6",
                        "name": "Newsletter Subscribers",
                        "group": "Engagement",
                        "description": "Contacts who opted in to the monthly newsletter",
                        "display_names": {
                          "en": "Newsletter"
                        }
                      }
                    ]
                  },
                  "kvp": {
                    "summary": "Key-value pair response (result_type=kvp)",
                    "value": {
                      "42": "Newsletter Subscribers",
                      "43": "Event Attendees"
                    }
                  },
                  "empty": {
                    "summary": "No tags",
                    "value": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a tag",
        "description": "Creates a new tag. `name` is required. Optional fields: `group`, `description`, `display_names`.",
        "operationId": "createTag",
        "tags": [
          "Tags"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagCreate"
              },
              "examples": {
                "basic": {
                  "summary": "Create a basic tag",
                  "value": {
                    "name": "Newsletter Subscribers"
                  }
                },
                "with_group": {
                  "summary": "Create with group and description",
                  "value": {
                    "name": "Annual Conference Attendees",
                    "group": "Events",
                    "description": "Members who attend our annual conference"
                  }
                },
                "with_display_names": {
                  "summary": "Create with translated display names",
                  "value": {
                    "name": "Newsletter Subscribers",
                    "display_names": {
                      "en": "Newsletter",
                      "fr": "Infolettre"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tag created successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateSuccessResponse"
                },
                "example": {
                  "success": true,
                  "result_text": "Created",
                  "result_data": {
                    "id": "42",
                    "external_id": "a1b2c3d4e5f6",
                    "name": "Newsletter Subscribers",
                    "group": "Engagement",
                    "description": "Contacts who opted in to the monthly newsletter",
                    "display_names": {
                      "en": "Newsletter"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "name_required": {
                    "summary": "Missing name",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "The field 'name' is required"
                        ]
                      }
                    }
                  },
                  "invalid_group": {
                    "summary": "Group not found",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "Invalid 'group': 'Nonexistent Group'"
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/tags/{id}": {
      "get": {
        "summary": "Get a single tag",
        "description": "Returns a single tag by its ID. Returns an empty array (`[]`) if the ID is not found.",
        "operationId": "getTag",
        "tags": [
          "Tags"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TagId"
          },
          {
            "$ref": "#/components/parameters/Fields"
          }
        ],
        "responses": {
          "200": {
            "description": "The requested tag, or an empty array if not found.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Tag"
                    },
                    {
                      "type": "array",
                      "maxItems": 0
                    }
                  ]
                },
                "examples": {
                  "found": {
                    "summary": "Tag found",
                    "value": {
                      "id": "42",
                      "external_id": "a1b2c3d4e5f6",
                      "name": "Newsletter Subscribers",
                      "group": "Engagement",
                      "description": "Contacts who opted in to the monthly newsletter",
                      "display_names": {
                        "en": "Newsletter"
                      }
                    }
                  },
                  "not_found": {
                    "summary": "Tag not found",
                    "value": []
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update a tag",
        "description": "Updates one or more fields on an existing tag. `name`, `group`, `description`, and `display_names` are updatable. `external_id` is silently ignored if included. If `id` is included in the body, it must match the `{id}` in the URL — if they differ, a validation envelope is returned.",
        "operationId": "updateTag",
        "tags": [
          "Tags"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TagId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagUpdate"
              },
              "examples": {
                "rename": {
                  "summary": "Rename the tag",
                  "value": {
                    "name": "Updated Tag Name"
                  }
                },
                "assign_group": {
                  "summary": "Assign to a group",
                  "value": {
                    "group": "Certification Programs"
                  }
                },
                "remove_group": {
                  "summary": "Remove group assignment",
                  "value": {
                    "group": ""
                  }
                },
                "update_display_names": {
                  "summary": "Update display names",
                  "value": {
                    "display_names": {
                      "en": "Organic",
                      "fr": "Biologique"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tag updated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateSuccessResponse"
                },
                "example": {
                  "success": true,
                  "result_text": "Updated",
                  "result_data": {
                    "id": "42",
                    "external_id": "a1b2c3d4e5f6",
                    "name": "Updated Tag Name",
                    "group": "Certification Programs",
                    "description": "Updated description",
                    "display_names": {
                      "en": "Updated Tag"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error, tag not found, or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "not_found": {
                    "summary": "Tag not found",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "Item with id '999999' not found"
                        ]
                      }
                    }
                  },
                  "invalid_group": {
                    "summary": "Group not found",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "Invalid 'group': 'Does Not Exist'"
                        ]
                      }
                    }
                  },
                  "id_mismatch": {
                    "summary": "id in body does not match URL id",
                    "value": {
                      "success": false,
                      "result_text": "Provided 'id': 42 does not match 'id' in request body (999)",
                      "result_data": []
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete a tag",
        "description": "Permanently deletes a tag and all contact-to-tag associations. Contacts are not deleted — they simply lose their assignment to this tag.",
        "operationId": "deleteTag",
        "tags": [
          "Tags"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TagId"
          }
        ],
        "responses": {
          "200": {
            "description": "Tag deleted successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteSuccessResponse"
                },
                "example": {
                  "success": true,
                  "result_text": "Deleted",
                  "result_data": []
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/NotFoundMutate"
          }
        }
      }
    },
    "/tags/{id}/contacts": {
      "post": {
        "summary": "Add contacts to a tag",
        "description": "Bulk-assigns contacts to a tag. Accepts either `contact_ids` or `contact_emails` (not both). Maximum 1,000 items per request. The operation is idempotent — adding a contact that is already tagged is a no-op.",
        "operationId": "addTagContacts",
        "tags": [
          "Tag Contacts"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TagId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactsRequest"
              },
              "examples": {
                "by_ids": {
                  "summary": "Add by contact IDs",
                  "value": {
                    "contact_ids": [
                      101,
                      102,
                      103
                    ]
                  }
                },
                "by_emails": {
                  "summary": "Add by email addresses",
                  "value": {
                    "contact_emails": [
                      "alice@example.com",
                      "bob@example.com"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Operation completed. Check `success` and `result_data` for details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactsSuccessResponse"
                },
                "examples": {
                  "all_found": {
                    "summary": "All contacts found and updated",
                    "value": {
                      "success": true,
                      "result_text": "Set to contacts",
                      "result_data": {
                        "processed": 3
                      }
                    }
                  },
                  "some_not_found": {
                    "summary": "Some contacts not found",
                    "value": {
                      "success": true,
                      "result_text": "Set to contacts. Some contacts not found",
                      "result_data": {
                        "processed": 3,
                        "not_found": [
                          "ghost@example.com"
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error or tag not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "no_field": {
                    "summary": "Neither contact_ids nor contact_emails provided",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "Either 'contact_ids' or 'contact_emails' must be provided"
                        ]
                      }
                    }
                  },
                  "both_fields": {
                    "summary": "Both contact_ids and contact_emails provided",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "Provide either 'contact_ids' or 'contact_emails', not both"
                        ]
                      }
                    }
                  },
                  "tag_not_found": {
                    "summary": "Tag not found",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "Item with id '999999' not found"
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Remove contacts from a tag",
        "description": "Bulk-removes contacts from a tag. Accepts either `contact_ids` or `contact_emails` (not both). Maximum 1,000 items per request. The operation is idempotent — removing a contact that is not tagged is a no-op.",
        "operationId": "removeTagContacts",
        "tags": [
          "Tag Contacts"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/TagId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactsRequest"
              },
              "examples": {
                "by_ids": {
                  "summary": "Remove by contact IDs",
                  "value": {
                    "contact_ids": [
                      101,
                      102
                    ]
                  }
                },
                "by_emails": {
                  "summary": "Remove by email addresses",
                  "value": {
                    "contact_emails": [
                      "alice@example.com"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Operation completed. Check `success` and `result_data` for details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactsSuccessResponse"
                },
                "example": {
                  "success": true,
                  "result_text": "Set to contacts",
                  "result_data": {
                    "processed": 2
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error or tag not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  }
}
