{
  "openapi": "3.1.0",
  "info": {
    "title": "Envoke Sender Identity API",
    "version": "1.0.0",
    "description": "Full CRUD API for managing sender identities. All endpoints require HTTP Basic Auth and return JSON. The default sender identity cannot be deleted — promote a different identity first."
  },
  "servers": [
    {
      "url": "https://e1.envoke.com/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "basicAuth": []
    }
  ],
  "tags": [
    {
      "name": "Senders",
      "description": "Operations on sender identities."
    }
  ],
  "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": {
      "DkimStatus": {
        "type": "object",
        "description": "DKIM verification status for the sender's domain.",
        "required": [
          "verified",
          "domain"
        ],
        "properties": {
          "verified": {
            "type": "boolean",
            "description": "true if DKIM is configured and verified for this domain; false if setup is incomplete."
          },
          "domain": {
            "type": "string",
            "description": "The domain extracted from the sender's email address.",
            "examples": [
              "harborview.gov"
            ]
          }
        }
      },
      "Sender": {
        "type": "object",
        "description": "A sender identity.",
        "required": [
          "id",
          "name",
          "email",
          "is_default"
        ],
        "properties": {
          "id": {
            "type": "string",
            "readOnly": true,
            "description": "Unique identifier assigned on creation. Returned as a string.",
            "examples": [
              "42"
            ]
          },
          "name": {
            "type": "string",
            "description": "The sender display name shown in the From field.",
            "examples": [
              "City of Harborview"
            ]
          },
          "email": {
            "type": "string",
            "description": "The sender email address. Must be a domain the organisation controls.",
            "examples": [
              "communications@harborview.gov"
            ]
          },
          "is_default": {
            "type": "boolean",
            "readOnly": true,
            "description": "true if this is the account's default sender identity, false otherwise. Exactly one identity is always the default. Use POST /senders/{id}/default to change it."
          }
        }
      },
      "SenderFull": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Sender"
          },
          {
            "type": "object",
            "required": [
              "dkim_status"
            ],
            "properties": {
              "dkim_status": {
                "$ref": "#/components/schemas/DkimStatus",
                "description": "DKIM verification status for the sender's domain. Returned on create and update only. When verified is false, configure DKIM DNS records for this domain to improve deliverability."
              }
            }
          }
        ]
      },
      "SenderCreate": {
        "type": "object",
        "description": "Request body for creating a new sender identity. Both name and email are required.",
        "required": [
          "name",
          "email"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Sender display name. Double quotes are not allowed.",
            "examples": [
              "City of Harborview"
            ]
          },
          "email": {
            "type": "string",
            "description": "Sender email address. Must use a domain the organisation controls. Free and personal email providers are not accepted.",
            "examples": [
              "communications@harborview.gov"
            ]
          }
        }
      },
      "SenderUpdate": {
        "type": "object",
        "description": "Request body for updating a sender identity. At least one of name or email must be provided. If id is included in the body it must match the {id} in the URL.",
        "minProperties": 1,
        "properties": {
          "name": {
            "type": "string",
            "description": "Updated sender display name. Double quotes are not allowed.",
            "examples": [
              "Office of Communications"
            ]
          },
          "email": {
            "type": "string",
            "description": "Updated sender email address.",
            "examples": [
              "info@harborview.gov"
            ]
          }
        }
      },
      "CreateSuccessResponse": {
        "type": "object",
        "description": "Returned on successful sender creation.",
        "required": [
          "success",
          "result_text",
          "result_data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "result_text": {
            "type": "string",
            "const": "Created"
          },
          "result_data": {
            "$ref": "#/components/schemas/SenderFull"
          }
        }
      },
      "UpdateSuccessResponse": {
        "type": "object",
        "description": "Returned on successful sender update.",
        "required": [
          "success",
          "result_text",
          "result_data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "result_text": {
            "type": "string",
            "const": "Updated"
          },
          "result_data": {
            "$ref": "#/components/schemas/SenderFull"
          }
        }
      },
      "DeleteSuccessResponse": {
        "type": "object",
        "description": "Returned on successful sender 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
          }
        }
      },
      "SetDefaultSuccessResponse": {
        "type": "object",
        "description": "Returned when the default sender is successfully updated.",
        "required": [
          "success",
          "result_text",
          "result_data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "result_text": {
            "type": "string",
            "const": "Updated"
          },
          "result_data": {
            "type": "array",
            "maxItems": 0
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Returned for general request errors (not validation failures).",
        "required": [
          "success",
          "result_text",
          "result_data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "result_text": {
            "type": "string"
          },
          "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": {
      "SenderId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The unique ID of the sender identity.",
        "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 hard cap is lifted.",
        "schema": {
          "type": "string"
        },
        "example": "id,name,email"
      },
      "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": {
      "NotFoundMutate": {
        "description": "The requested sender 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'",
              "errors": [
                "Item with id '42' not found"
              ]
            }
          }
        }
      }
    }
  },
  "paths": {
    "/senders": {
      "get": {
        "summary": "List sender identities",
        "description": "Returns a paginated array of sender identities for the authenticated account. Supports filtering by id, name, email, and is_default. Note: sorting is not currently supported.",
        "operationId": "listSenders",
        "tags": [
          "Senders"
        ],
        "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 sender ID. Supports operators: `(ne)`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter[name]",
            "in": "query",
            "description": "Filter by sender display name. Supports operators: `(ne)`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter[email]",
            "in": "query",
            "description": "Filter by sender email address. Supports operators: `(ne)`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter[is_default]",
            "in": "query",
            "description": "Filter by default status. Use 1 to return only the default sender, 0 to return only non-default senders.",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A list of sender identities.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Sender"
                      }
                    },
                    {
                      "type": "object",
                      "description": "Key-value map of sender ID to name.",
                      "additionalProperties": {
                        "type": "string"
                      }
                    }
                  ]
                },
                "examples": {
                  "array": {
                    "summary": "Default array response",
                    "value": [
                      {
                        "id": "1",
                        "name": "City of Harborview",
                        "email": "communications@harborview.gov",
                        "is_default": true
                      },
                      {
                        "id": "2",
                        "name": "Parks & Recreation",
                        "email": "parks@harborview.gov",
                        "is_default": false
                      }
                    ]
                  },
                  "kvp": {
                    "summary": "Key-value pair response (result_type=kvp)",
                    "value": {
                      "1": "City of Harborview",
                      "2": "Parks & Recreation"
                    }
                  },
                  "empty": {
                    "summary": "No senders found",
                    "value": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid query parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a sender identity",
        "description": "Creates a new sender identity. Both name and email are required. The first identity created is automatically set as the account's default.",
        "operationId": "createSender",
        "tags": [
          "Senders"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SenderCreate"
              },
              "examples": {
                "basic": {
                  "summary": "Create a sender identity",
                  "value": {
                    "name": "City of Harborview",
                    "email": "communications@harborview.gov"
                  }
                },
                "department": {
                  "summary": "Create a department sender",
                  "value": {
                    "name": "Parks & Recreation",
                    "email": "parks@harborview.gov"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sender created successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateSuccessResponse"
                },
                "example": {
                  "success": true,
                  "result_text": "Created",
                  "result_data": {
                    "id": "1",
                    "name": "City of Harborview",
                    "email": "communications@harborview.gov",
                    "is_default": true,
                    "dkim_status": {
                      "verified": true,
                      "domain": "harborview.gov"
                    }
                  }
                }
              }
            }
          },
          "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"
                        ]
                      }
                    }
                  },
                  "email_required": {
                    "summary": "Missing email",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "Email is required"
                        ]
                      }
                    }
                  },
                  "invalid_email": {
                    "summary": "Invalid email format",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "Email address is not valid"
                        ]
                      }
                    }
                  },
                  "blocked_domain": {
                    "summary": "Free or personal email provider",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "Third party email providers such as gmail.com, yahoo.com, etc. cannot be used as senders"
                        ]
                      }
                    }
                  },
                  "duplicate": {
                    "summary": "Duplicate name and email combination",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "A sender with this name and email already exists"
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/senders/{id}": {
      "get": {
        "summary": "Get a single sender identity",
        "description": "Returns a single sender identity by ID. Returns an empty array ([]) if the ID is not found.",
        "operationId": "getSender",
        "tags": [
          "Senders"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderId"
          },
          {
            "$ref": "#/components/parameters/Fields"
          }
        ],
        "responses": {
          "200": {
            "description": "The requested sender identity, or an empty array if not found.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Sender"
                    },
                    {
                      "type": "array",
                      "maxItems": 0
                    }
                  ]
                },
                "examples": {
                  "found": {
                    "summary": "Sender found",
                    "value": {
                      "id": "1",
                      "name": "City of Harborview",
                      "email": "communications@harborview.gov",
                      "is_default": true
                    }
                  },
                  "not_found": {
                    "summary": "Sender not found",
                    "value": []
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update a sender identity",
        "description": "Updates the name and/or email of an existing sender identity. At least one field must be provided. id and is_default are read-only and cannot be changed via PATCH — to change the default sender use POST /senders/{id}/default. If id is included in the request body it must match the {id} in the URL.",
        "operationId": "updateSender",
        "tags": [
          "Senders"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SenderUpdate"
              },
              "examples": {
                "rename": {
                  "summary": "Update the name only",
                  "value": {
                    "name": "Office of Communications"
                  }
                },
                "update_email": {
                  "summary": "Update the email only",
                  "value": {
                    "email": "info@harborview.gov"
                  }
                },
                "both": {
                  "summary": "Update both name and email",
                  "value": {
                    "name": "Office of Communications",
                    "email": "info@harborview.gov"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sender updated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateSuccessResponse"
                },
                "example": {
                  "success": true,
                  "result_text": "Updated",
                  "result_data": {
                    "id": "2",
                    "name": "Office of Communications",
                    "email": "info@harborview.gov",
                    "is_default": false,
                    "dkim_status": {
                      "verified": true,
                      "domain": "harborview.gov"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error, sender not found, or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ValidationErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "not_found": {
                    "summary": "Sender not found",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "errors": [
                        "Item with id '42' not found"
                      ]
                    }
                  },
                  "id_mismatch": {
                    "summary": "id in body does not match URL id",
                    "value": {
                      "success": false,
                      "result_text": "Provided 'id': 2 does not match 'id' in request body (999)",
                      "result_data": []
                    }
                  },
                  "invalid_email": {
                    "summary": "Invalid email format",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "Email address is not valid"
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete a sender identity",
        "description": "Permanently deletes a sender identity. The default sender cannot be deleted — use POST /senders/{id}/default to promote a different identity first.",
        "operationId": "deleteSender",
        "tags": [
          "Senders"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderId"
          }
        ],
        "responses": {
          "200": {
            "description": "Sender deleted successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteSuccessResponse"
                },
                "example": {
                  "success": true,
                  "result_text": "Deleted",
                  "result_data": []
                }
              }
            }
          },
          "400": {
            "description": "Sender not found or sender is the default.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationErrorResponse"
                },
                "examples": {
                  "not_found": {
                    "summary": "Sender not found",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "errors": [
                        "Item with id '42' not found"
                      ]
                    }
                  },
                  "is_default": {
                    "summary": "Cannot delete the default sender",
                    "value": {
                      "success": false,
                      "result_text": "Validation failed, see 'result_data' -> 'errors'",
                      "result_data": {
                        "errors": [
                          "The default sender identity cannot be deleted"
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/senders/{id}/default": {
      "post": {
        "summary": "Set the default sender",
        "description": "Promotes the specified sender identity to be the account's default. Clears the default flag from all other identities and syncs the account's default From name and email. The default sender is used automatically when no sender is explicitly specified in a campaign.",
        "operationId": "setDefaultSender",
        "tags": [
          "Senders"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SenderId"
          }
        ],
        "responses": {
          "200": {
            "description": "Default sender updated successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SetDefaultSuccessResponse"
                },
                "example": {
                  "success": true,
                  "result_text": "Updated",
                  "result_data": []
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/NotFoundMutate"
          }
        }
      }
    }
  }
}
