{
  "openapi": "3.0.3",
  "info": {
    "title": "Mailketing API v2",
    "version": "2.0.2",
    "description": "Email marketing API untuk mengirim email transaksional, cek kredit, daftar sender terverifikasi, kelola list, dan tambah subscriber.",
    "contact": {
      "name": "Mailketing Support",
      "email": "support@mailketing.co.id",
      "url": "https://mailketing.co.id"
    }
  },
  "servers": [
    {
      "url": "https://api.mailketing.co.id/api/v2",
      "description": "Production API v2"
    }
  ],
  "security": [
    { "ApiTokenAuth": [] }
  ],
  "components": {
    "securitySchemes": {
      "ApiTokenAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Token",
        "description": "API token dari dashboard Mailketing. Bisa juga dikirim via query param ?api_token=xxx atau Authorization: Bearer xxx"
      }
    },
    "schemas": {
      "SuccessResponse": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": true },
          "data": { "type": "object" },
          "message": { "type": "string", "example": "OK" }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": false },
          "data": { "type": "null" },
          "message": { "type": "string", "example": "Invalid API token" },
          "errors": { "type": "object" }
        }
      },
      "CorporateVerifySenderRequest": {
        "type": "object",
        "required": ["email"],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email sender yang akan diverifikasi, misal contoh@regrow.id",
            "example": "contoh@regrow.id"
          }
        }
      },
      "CorporateVerifySenderResponse": {
        "type": "object",
        "properties": {
          "domain":     { "type": "string", "example": "regrow.id" },
          "esp_domain": { "type": "string", "example": "balaschat.my.id" },
          "spf": {
            "type": "object",
            "properties": {
              "valid": { "type": "boolean" },
              "found": { "type": "string", "nullable": true },
              "guide": { "type": "string", "nullable": true },
              "suggested_value": { "type": "string", "nullable": true }
            }
          },
          "dkim": {
            "type": "object",
            "properties": {
              "valid":       { "type": "boolean" },
              "host":        { "type": "string" },
              "guide":       { "type": "string", "nullable": true },
              "cname_host":  { "type": "string", "nullable": true },
              "cname_value": { "type": "string", "nullable": true }
            }
          }
        }
      },
      "SendRequest": {
        "type": "object",
        "required": ["api_token", "from_name", "from_email", "subject", "recipient", "content"],
        "properties": {
          "api_token": { "type": "string", "description": "API token akun Mailketing" },
          "from_name": { "type": "string", "description": "Nama pengirim", "maxLength": 255 },
          "from_email": { "type": "string", "format": "email", "description": "Email pengirim (domain harus terverifikasi)" },
          "subject": { "type": "string", "description": "Subject email", "maxLength": 998 },
          "recipient": { "type": "string", "format": "email", "description": "Email penerima" },
          "content": { "type": "string", "description": "Konten email (HTML atau plain text, max 300KB untuk plain text)" },
          "attach1": { "type": "string", "format": "uri", "description": "URL attachment 1 (opsional)" },
          "attach2": { "type": "string", "format": "uri", "description": "URL attachment 2 (opsional)" },
          "attach3": { "type": "string", "format": "uri", "description": "URL attachment 3 (opsional)" }
        }
      },
      "CreditsResponse": {
        "type": "object",
        "properties": {
          "credits": { "type": "integer", "example": 1500 },
          "email": { "type": "string", "format": "email", "example": "user@example.com" }
        }
      },
      "SendersResponse": {
        "type": "object",
        "properties": {
          "senders": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "email": { "type": "string", "format": "email" }
              }
            }
          }
        }
      },
      "ListsResponse": {
        "type": "object",
        "properties": {
          "lists": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "list_id": { "type": "integer", "example": 1 },
                "list_name": { "type": "string", "example": "Newsletter" }
              }
            }
          }
        }
      },
      "SubscriberRequest": {
        "type": "object",
        "required": ["list_id", "email"],
        "properties": {
          "api_token": { "type": "string", "description": "API token akun Mailketing (opsional jika dikirim via header/query)" },
          "list_id": { "type": "integer", "description": "ID list tujuan (dari GET /lists)" },
          "email": { "type": "string", "format": "email", "description": "Email subscriber", "maxLength": 255 },
          "mobile": { "type": "string", "description": "Nomor HP, auto-normalize ke format 628...", "maxLength": 30 },
          "first_name": { "type": "string", "description": "Nama depan (alphanumeric & spasi)", "maxLength": 255 },
          "last_name": { "type": "string", "description": "Nama belakang (alphanumeric & spasi)", "maxLength": 255 },
          "title": { "type": "string", "description": "Title (Mr/Mrs/dll)", "maxLength": 100 },
          "birth_date": { "type": "string", "format": "date", "description": "Tanggal lahir format YYYY-MM-DD" },
          "city": { "type": "string", "description": "Kota", "maxLength": 100 },
          "country": { "type": "string", "description": "Negara", "maxLength": 100 },
          "company": { "type": "string", "description": "Perusahaan", "maxLength": 255 },
          "post_code": { "type": "string", "description": "Kode pos", "maxLength": 20 },
          "state": { "type": "string", "description": "Provinsi / state", "maxLength": 100 },
          "phone": { "type": "string", "description": "Nomor telepon", "maxLength": 30 },
          "fax": { "type": "string", "description": "Nomor fax", "maxLength": 30 }
        },
        "additionalProperties": { "type": "string", "description": "Custom fields: key = field_name, value = string" }
      },
      "SubscriberResponse": {
        "type": "object",
        "properties": {
          "email_list_id": { "type": ["integer", "null"], "example": 123 },
          "list_id": { "type": "integer", "example": 1 },
          "status": { "type": "string", "enum": ["added", "already_exists"] }
        }
      }
    }
  },
  "paths": {
    "/corporate/send": {
      "post": {
        "tags": ["Corporate API"],
        "summary": "Send Email",
        "description": "Mengirim email transaksional via Corporate API. from_email domain harus match esp_domain. Queue: sendemailcorv2.",
        "security": [{ "ApiTokenAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SendRequest" },
              "example": {
                "from_name": "John Doe",
                "from_email": "john@regrow.id",
                "subject": "Hello from Corporate API",
                "recipient": "target@example.com",
                "content": "<h1>Hello!</h1><p>Email via Corporate API.</p>"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email berhasil di-queue",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    { "properties": { "data": { "type": "object", "properties": { "message_id": { "type": "string" } } } } }
                  ]
                }
              }
            }
          },
          "401": { "description": "API token tidak valid" },
          "402": { "description": "Kredit habis" },
          "403": { "description": "Bukan akun corporate atau from_email domain tidak match esp_domain" },
          "422": { "description": "Validasi input gagal atau esp_domain belum di-set" },
          "429": { "description": "Terlalu banyak request gagal (30/menit per IP)" }
        }
      }
    },
    "/corporate/verify-sender": {
      "post": {
        "tags": ["Corporate API"],
        "summary": "Verify Sender Domain",
        "description": "Memverifikasi konfigurasi DNS (SPF dan DKIM) untuk domain sender yang akan digunakan via Corporate API. Hanya untuk akun dengan bisnisapi = 1.",
        "security": [{ "ApiTokenAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CorporateVerifySenderRequest" },
              "example": { "email": "contoh@regrow.id" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Domain valid — SPF dan DKIM terverifikasi",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    { "properties": { "data": { "$ref": "#/components/schemas/CorporateVerifySenderResponse" } } }
                  ]
                }
              }
            }
          },
          "401": { "description": "API token tidak valid" },
          "403": { "description": "Akun bukan corporate (bisnisapi != 1)" },
          "422": { "description": "Validasi gagal / SPF atau DKIM tidak valid / esp_domain belum di-set" },
          "429": { "description": "Terlalu banyak request gagal (30/menit per IP)" }
        }
      }
    },
    "/send": {
      "post": {
        "tags": ["Email"],
        "summary": "Kirim email transaksional",
        "description": "Mengirim email transaksional. Domain pengirim harus sudah diverifikasi.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SendRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email berhasil diterima untuk diproses. message_id selalu dibuat otomatis oleh Mailketing dengan format <api.{random}@domain> (tidak bisa diisi sendiri)",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    { "properties": { "data": { "properties": { "message_id": { "type": "string", "example": "<api.a1b2c3d4e5f67890123456@domain.com>", "description": "Message ID yang dibuat otomatis oleh Mailketing (tidak bisa diisi sendiri). Simpan untuk mencocokkan event webhook." } } } } }
                  ]
                }
              }
            }
          },
          "401": { "description": "Token invalid" },
          "402": { "description": "Kredit habis" },
          "403": { "description": "Sender domain tidak terverifikasi" },
          "422": { "description": "Validasi input gagal" },
          "429": { "description": "Terlalu banyak request gagal. Hanya request gagal yang di-rate limit (30/menit per IP), request sukses tidak." }
        }
      }
    },
    "/credits": {
      "get": {
        "tags": ["Account"],
        "summary": "Cek sisa kredit",
        "description": "Mendapatkan jumlah kredit tersisa untuk akun.",
        "responses": {
          "200": {
            "description": "Informasi kredit",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    { "properties": { "data": { "$ref": "#/components/schemas/CreditsResponse" } } }
                  ]
                }
              }
            }
          },
          "401": { "description": "Token invalid" }
        }
      }
    },
    "/senders": {
      "get": {
        "tags": ["Account"],
        "summary": "Daftar sender terverifikasi",
        "description": "Mendapatkan semua email pengirim yang sudah diverifikasi untuk akun.",
        "responses": {
          "200": {
            "description": "Daftar sender",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    { "properties": { "data": { "$ref": "#/components/schemas/SendersResponse" } } }
                  ]
                }
              }
            }
          },
          "401": { "description": "Token invalid" }
        }
      }
    },
    "/lists": {
      "get": {
        "tags": ["List"],
        "summary": "Daftar list subscriber",
        "description": "Mendapatkan semua list subscriber milik akun (tidak termasuk list internal 'ALL CONTACT').",
        "responses": {
          "200": {
            "description": "Daftar list",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    { "properties": { "data": { "$ref": "#/components/schemas/ListsResponse" } } }
                  ]
                }
              }
            }
          },
          "401": { "description": "Token invalid" }
        }
      }
    },
    "/subscribers": {
      "post": {
        "tags": ["List"],
        "summary": "Tambah subscriber ke list",
        "description": "Menambahkan subscriber ke list. Jika email sudah ada di list tersebut, return status `already_exists` (tetap HTTP 200, bukan error).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SubscriberRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Subscriber berhasil ditambahkan atau sudah ada",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    { "$ref": "#/components/schemas/SuccessResponse" },
                    { "properties": { "data": { "$ref": "#/components/schemas/SubscriberResponse" } } }
                  ]
                }
              }
            }
          },
          "401": { "description": "Token invalid" },
          "404": { "description": "List tidak ditemukan atau bukan milik akun ini" },
          "422": { "description": "Validasi input gagal" },
          "429": { "description": "Terlalu banyak request gagal. Hanya request gagal yang di-rate limit (30/menit per IP), request sukses tidak." }
        }
      }
    }
  }
}
