{
  "openapi": "3.0.3",
  "info": {
    "title": "SaringID API",
    "version": "1.0.0",
    "description": "API moderasi konten teks berbahasa Indonesia. Autentikasi via header X-API-Key (atau Bearer token, atau query api_key).\n\nScope API key:\n- moderate: endpoint tulis (POST /v1/moderate, POST /v1/moderate/batch)\n- usage: endpoint baca (GET /v1/usage, GET /v1/analytics)\n\nMode sandbox: API key bertanda sandbox tidak memakan kuota, tidak dicatat ke usage log/analitik, dan response menyertakan `\"sandbox\": true`.\n\nSetiap response API menyertakan header `X-RateLimit-Limit`, `X-RateLimit-Remaining`, dan `X-RateLimit-Reset` (detik)."
  },
  "servers": [
    {
      "url": "https://domain-kamu",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      }
    },
    "schemas": {
      "ModerateResult": {
        "type": "object",
        "properties": {
          "is_offensive": {
            "type": "boolean"
          },
          "level": {
            "type": "integer",
            "description": "0=bersih sampai 5=sangat kasar"
          },
          "confidence": {
            "type": "number"
          },
          "matched_words": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kata": {
                  "type": "string"
                },
                "level": {
                  "type": "integer"
                }
              }
            }
          },
          "pii": {
            "type": "object",
            "properties": {
              "found": {
                "type": "boolean"
              },
              "types": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "redacted": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "example": false
          },
          "error": {
            "type": "string"
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/moderate": {
      "post": {
        "summary": "Moderasi satu teks",
        "tags": [
          "Moderasi"
        ],
        "description": "Butuh scope `moderate`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string",
                    "maxLength": 10000
                  },
                  "detailed": {
                    "type": "boolean",
                    "default": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ModerateResult"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "API key tidak valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope tidak cukup / tanpa langganan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Kuota habis / rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/moderate/batch": {
      "post": {
        "summary": "Moderasi banyak teks",
        "tags": [
          "Moderasi"
        ],
        "description": "Butuh scope `moderate`. Maksimal 50 teks per request.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "texts"
                ],
                "properties": {
                  "texts": {
                    "type": "array",
                    "maxItems": 50,
                    "items": {
                      "type": "string"
                    }
                  },
                  "detailed": {
                    "type": "boolean",
                    "default": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ModerateResult"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "flagged": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "API key tidak valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Kuota habis / rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/usage": {
      "get": {
        "summary": "Cek sisa kuota",
        "tags": [
          "Akun"
        ],
        "description": "Butuh scope `usage`.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "plan": {
                          "type": "string"
                        },
                        "team": {
                          "type": "string",
                          "nullable": true
                        },
                        "requests_today": {
                          "type": "integer"
                        },
                        "daily_quota": {
                          "type": "integer"
                        },
                        "daily_remaining": {
                          "type": "integer"
                        },
                        "per_minute_quota": {
                          "type": "integer"
                        },
                        "requests_last_minute": {
                          "type": "integer"
                        },
                        "resets_at": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "API key tidak valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/analytics": {
      "get": {
        "summary": "Ringkasan analitik",
        "tags": [
          "Akun"
        ],
        "description": "Butuh scope `usage`. Agregat seluruh API key milik akun.",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "period_days": {
                          "type": "integer"
                        },
                        "total_requests": {
                          "type": "integer"
                        },
                        "total_flagged": {
                          "type": "integer"
                        },
                        "flag_rate_percent": {
                          "type": "number"
                        },
                        "trend": {
                          "type": "object",
                          "properties": {
                            "dates": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            },
                            "requests": {
                              "type": "array",
                              "items": {
                                "type": "integer"
                              }
                            },
                            "flagged": {
                              "type": "array",
                              "items": {
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "top_words": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "per_key": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "API key tidak valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope tidak cukup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/custom-words": {
      "get": {
        "summary": "Daftar kata custom",
        "tags": [
          "Kata Custom"
        ],
        "description": "Butuh scope `usage`. Maksimal 500 kata.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "kata": {
                            "type": "string"
                          },
                          "action": {
                            "type": "string",
                            "enum": [
                              "block",
                              "allow"
                            ]
                          },
                          "level": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "API key tidak valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Tambah/ubah kata custom",
        "tags": [
          "Kata Custom"
        ],
        "description": "Butuh scope `moderate`. action=block memaksa kata dianggap ofensif (level 2-5), action=allow memutihkan kata.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "kata",
                  "action"
                ],
                "properties": {
                  "kata": {
                    "type": "string"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "block",
                      "allow"
                    ]
                  },
                  "level": {
                    "type": "integer",
                    "minimum": 2,
                    "maximum": 5
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Dibuat",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "kata": {
                          "type": "string"
                        },
                        "action": {
                          "type": "string",
                          "enum": [
                            "block",
                            "allow"
                          ]
                        },
                        "level": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "API key tidak valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope tidak cukup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/custom-words/{kata}": {
      "delete": {
        "summary": "Hapus kata custom",
        "tags": [
          "Kata Custom"
        ],
        "description": "Butuh scope `moderate`.",
        "parameters": [
          {
            "name": "kata",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "API key tidak valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope tidak cukup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Kata tidak ditemukan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/feedback": {
      "post": {
        "summary": "Laporkan keputusan moderasi yang salah",
        "description": "Putaran tertutup kualitas: laporkan teks yang menurutmu salah dimoderasi beserta level yang benar (0 = seharusnya bersih). Masuk antrean review admin. Tidak tersedia untuk key zero-retention.",
        "tags": [
          "Moderasi"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text",
                  "correct_level"
                ],
                "properties": {
                  "text": {
                    "type": "string",
                    "maxLength": 5000,
                    "example": "kamu goblok"
                  },
                  "correct_level": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 5,
                    "example": 3,
                    "description": "Level yang benar menurut pelapor (0 = seharusnya bersih)"
                  },
                  "comment": {
                    "type": "string",
                    "maxLength": 500,
                    "example": "konteks candaan antar teman"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Laporan diterima",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "Scope tidak cukup / key zero-retention"
          },
          "422": {
            "description": "Validasi gagal"
          }
        }
      }
    }
  }
}