> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Moderation API

> Saring prompt dan gambar sebelum produk AI Anda membuat konten, lalu dapatkan keputusan allow, flag, atau deny beserta skor untuk 17 kategori konten.

<CardGroup cols={2}>
  <Card title="Screen a Prompt" icon="shield-check" href="/api-reference/moderation/screen">
    Kirim teks, gambar, atau keduanya, lalu dapatkan keputusan.
  </Card>

  <Card title="Get Moderation Usage" icon="chart-column" href="/api-reference/moderation/get-usage">
    Lihat screen yang dapat ditagihkan dan tagihan Anda berikutnya.
  </Card>
</CardGroup>

## Ringkasan

Moderation API menyaring input pengguna sebelum produk AI Anda membuat konten darinya. Anda mengirim teks prompt, gambar, atau keduanya, dan Dodo Payments mengembalikan keputusan `allow`, `flag`, atau `deny`, bersama skor untuk setiap kategori konten.

Gunakan di depan model generasi gambar, video, atau teks apa pun yang menerima input dari pengguna Anda. Moderation API aktif secara default untuk setiap bisnis dan berjalan dengan API key Dodo Payments yang sudah ada, jadi Anda tidak perlu mendaftar lagi. Dodo Payments dapat menonaktifkannya untuk bisnis tertentu, dan panggilan kemudian mengembalikan `403` dengan `MODERATION_DISABLED`.

## Alasan Kami Membuat Moderation API

Produk generasi AI membuat konten baru dari apa pun yang diketik penggunanya. Anda tidak dapat meninjau setiap prompt secara manual, dan satu output berbahaya dapat menempatkan bisnis Anda dalam risiko.

Sebagai Merchant of Record Anda, Dodo Payments bertanggung jawab secara hukum dan reputasi atas apa yang dijual melalui platform. [Merchant Acceptance Policy](/miscellaneous/merchant-acceptance) meninjau alat generasi konten AI dan tidak mengizinkan impersonasi, deepfake, atau konten eksplisit, termasuk konten yang dihasilkan AI. Akun yang menghasilkan konten berbahaya, chargeback berlebihan, atau flag dari mitra pembayaran dapat ditinjau atau ditangguhkan.

Kami membuat Moderation API agar Anda dapat menghentikan konten ini sebelum model Anda membuatnya:

* **Saring sebelum membuat konten.** Prompt yang diblokir tidak pernah mencapai model Anda, sehingga tidak ada output berbahaya dan Anda tidak menghabiskan compute untuknya.
* **Cakup kategori yang penting untuk generasi.** Screen ini menilai 17 kategori, termasuk kemiripan dengan orang nyata, citra intim tanpa persetujuan, bahasa yang mengisyaratkan subjek masih di bawah umur, serta kombinasi orang nyata dengan konten seksual yang menandai deepfake seksual.
* **Integrasikan tanpa vendor lain.** API berjalan dengan API key Dodo Payments Anda, dan biayanya dipotong dari saldo Anda. Tidak ada kontrak, invoice, atau akun terpisah.
* **Jaga privasi konten pengguna.** Dodo Payments tidak menyimpan atau mencatat teks dan gambar yang Anda saring.

<Note>
  Moderation API adalah alat untuk penegakan aturan Anda sendiri. API ini tidak menggantikan Merchant Acceptance Policy, dan Anda tetap bertanggung jawab atas apa yang dihasilkan produk Anda.
</Note>

## Cara Kerjanya

Panggil Moderation API dari backend Anda setelah pengguna mengirimkan prompt dan sebelum model Anda berjalan:

```mermaid theme={null}
flowchart LR
  A[User submits a prompt] --> B[Your backend calls POST /moderation/screen]
  B -->|allow| C[Generate]
  B -->|flag| D[Apply your own policy]
  B -->|deny| E[Block the request]
  B -->|error, no verdict| E
```

Setiap panggilan adalah satu **screen**. Teks dan gambar yang dikirim dalam panggilan yang sama dihitung sebagai satu screen.

### Keputusan

Field `decision` berisi keputusan:

| Keputusan | Arti                                                                                  | Tindakan                                                                                             |
| --------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `allow`   | Konten lolos.                                                                         | Buat konten.                                                                                         |
| `flag`    | Konten melewati ambang kategori yang memerlukan penilaian. Ini bukan penolakan lunak. | Terapkan kebijakan Anda sendiri. Anda dapat memblokir, mengirim untuk ditinjau, atau membuat konten. |
| `deny`    | Konten tidak boleh dibuat.                                                            | Blokir permintaan dan tampilkan error kepada pengguna.                                               |

<Warning>
  Jangan membuat konten jika Anda tidak menerima keputusan. `503` berarti Dodo Payments tidak dapat menghasilkan keputusan, dan timeout atau error jaringan membuat Anda tidak memiliki keputusan. Perlakukan semua kondisi ini sebagai blokir dan minta pengguna mencoba lagi.
</Warning>

## Menyaring Prompt

Untuk menyaring prompt, kirim permintaan `POST` ke `/moderation/screen` dengan setidaknya salah satu dari `text` dan `image`. Permintaan ini menerima tiga field:

| Field        | Tipe   | Deskripsi                                                                                                                                              |
| ------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `text`       | string | Teks yang akan disaring, hingga 8.000 karakter.                                                                                                        |
| `image`      | string | Gambar yang akan disaring, dalam format base64, dengan atau tanpa awalan `data:image/...;base64,`.                                                     |
| `request_id` | string | Opsional. Identifier Anda untuk screen ini, seperti ID generasi, hingga 128 karakter tanpa karakter kontrol. Respons mengembalikannya tanpa perubahan. |

SDK TypeScript dan Python mengekspos endpoint sebagai `client.moderation.screen()`. Contoh ini memblokir generasi pada `deny`, pada `flag`, dan pada error apa pun:

<Note>
  Contoh ini memanggil live mode, karena hanya live mode yang menjalankan model moderasi. Test mode mengembalikan [mock verdicts](#testing-your-integration) dan tidak pernah menyaring konten. Screen live mode ditagihkan.
</Note>

<CodeGroup>
  ```typescript Node.js expandable theme={null}
  import DodoPayments from 'dodopayments';

  const client = new DodoPayments({
    bearerToken: process.env.DODO_PAYMENTS_API_KEY,
    environment: 'live_mode',
  });

  async function generateImage(prompt: string, generationId: string) {
    let verdict;
    try {
      verdict = await client.moderation.screen({
        text: prompt,
        request_id: generationId,
      });
    } catch (err) {
      // No verdict: do not generate.
      throw new Error('Moderation is unavailable. Try again in a moment.');
    }

    if (verdict.decision !== 'allow') {
      throw new Error('This prompt cannot be generated. Revise it and try again.');
    }

    return myModel.generate(prompt);
  }
  ```

  ```python Python expandable theme={null}
  import os
  from dodopayments import DodoPayments, APIError

  client = DodoPayments(
      bearer_token=os.environ["DODO_PAYMENTS_API_KEY"],
      environment="live_mode",
  )

  def generate_image(prompt: str, generation_id: str):
      try:
          verdict = client.moderation.screen(text=prompt, request_id=generation_id)
      except APIError:
          # No verdict: do not generate.
          raise RuntimeError("Moderation is unavailable. Try again in a moment.")

      if verdict.decision != "allow":
          raise ValueError("This prompt cannot be generated. Revise it and try again.")

      return my_model.generate(prompt)
  ```

  ```bash cURL theme={null}
  curl -X POST https://live.dodopayments.com/moderation/screen \
    -H "Authorization: Bearer $DODO_PAYMENTS_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "text": "a watercolor painting of a lighthouse at sunset",
      "request_id": "gen_7Hc2k9"
    }'
  ```
</CodeGroup>

Contoh ini memperlakukan `flag` seperti `deny`. Jika produk Anda mengizinkan sebagian konten yang ditandai, periksa `triggered` untuk mengambil keputusan berdasarkan kategori.

<Tip>
  Saring teks yang ditulis pengguna Anda, bukan template prompt yang membungkusnya. Template Anda sendiri sama pada setiap panggilan dan tidak menambahkan apa pun ke screen.
</Tip>

### Menyaring Gambar

Kirim gambar untuk menyaring gambar referensi yang diunggah, atau gambar yang dihasilkan sebelum menampilkannya. Gambar harus memenuhi persyaratan berikut:

* Formatnya adalah JPEG, PNG, WebP, GIF, atau BMP.
* String base64 berukuran paling banyak 6.991.530 karakter, dan gambar hasil decode berukuran paling banyak 5 MiB.
* Gambar berupa satu frame diam. Gambar GIF dan WebP animasi ditolak.
* Sisi terpanjang berukuran setidaknya 32 piksel.

Gambar yang gagal dalam salah satu pemeriksaan ini mengembalikan `400` dengan `MODERATION_INVALID_IMAGE`, atau `413` dengan `MODERATION_INPUT_TOO_LARGE` jika ukurannya terlalu besar.

Untuk menyaring gambar, baca file, encode sebagai base64, lalu kirim dalam `image`. Untuk menyaring gambar dan prompt-nya secara bersamaan, kirim `text` dan `image` dalam panggilan yang sama. Ini dihitung sebagai satu screen. Contoh ini menggunakan `client` dari contoh sebelumnya:

<CodeGroup>
  ```typescript Node.js expandable theme={null}
  import { readFile } from 'node:fs/promises';

  async function screenImage(path: string, prompt: string, generationId: string) {
    const image = (await readFile(path)).toString('base64');

    const verdict = await client.moderation.screen({
      image, // or `data:image/png;base64,${image}`
      text: prompt, // optional: screen the prompt with the image
      request_id: generationId,
    });

    return verdict.decision === 'allow';
  }
  ```

  ```python Python expandable theme={null}
  import base64

  def screen_image(path: str, prompt: str, generation_id: str) -> bool:
      with open(path, "rb") as f:
          image = base64.b64encode(f.read()).decode("ascii")

      verdict = client.moderation.screen(
          image=image,  # or f"data:image/png;base64,{image}"
          text=prompt,  # optional: screen the prompt with the image
          request_id=generation_id,
      )
      return verdict.decision == "allow"
  ```

  ```bash cURL expandable theme={null}
  # Builds the JSON body with jq, so a large image does not hit the shell argument limit.
  base64 < reference.png | tr -d '\n' \
    | jq -Rs '{image: ., text: "turn this photo into a watercolor painting", request_id: "gen_7Hc2k9"}' \
    | curl -X POST https://live.dodopayments.com/moderation/screen \
        -H "Authorization: Bearer $DODO_PAYMENTS_API_KEY" \
        -H "Content-Type: application/json" \
        --data @-
  ```
</CodeGroup>

Tangani error dari screen gambar dengan cara yang sama seperti screen teks: jika panggilan menghasilkan exception, jangan membuat konten.

## Membaca Respons

Respons mengembalikan keputusan dan bukti yang mendasarinya:

| Field                | Deskripsi                                                                                                                                                 |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `decision`           | Keputusan: `allow`, `flag`, atau `deny`.                                                                                                                  |
| `triggered`          | Kategori yang skornya melewati ambang kategori. Field ini dapat kosong pada `flag` dari pemeriksaan umum.                                                 |
| `compound_triggered` | `true` ketika kemiripan dengan orang nyata dan konten seksual secara bersamaan melewati ambang gabungannya, yaitu pola deepfake seksual.                  |
| `categories`         | Probabilitas, dari 0 hingga 1, bahwa konten termasuk dalam setiap kategori.                                                                               |
| `provenance`         | Cara setiap skor diukur: `targeted` melalui pemeriksaan untuk satu kategori tersebut, atau `broad` melalui pemeriksaan umum yang mencakup semua kategori. |
| `notes`              | Alasan keputusan yang dapat dibaca manusia. Susunan katanya dapat berubah, jadi jangan menguraikannya.                                                    |
| `normalized_applied` | `true` ketika teks juga disaring setelah obfuscation dihapus, seperti karakter tak terlihat atau karakter yang tampak serupa.                             |
| `passes`             | Jumlah pertanyaan ya/tidak yang dijawab model untuk screen ini.                                                                                           |
| `latency_ms`         | Durasi screen dalam milidetik.                                                                                                                            |
| `request_id`         | `request_id` yang Anda kirim, atau `null`.                                                                                                                |

Dasarkan logika Anda pada `decision` dan `triggered`. Setiap kategori memiliki ambangnya sendiri, sehingga satu batas skor dalam kode Anda tidak akan sesuai dengan keputusan.

### Kategori

Setiap respons menilai konten terhadap 17 kategori:

| Kategori                          | Cakupan                                                                   |
| --------------------------------- | ------------------------------------------------------------------------- |
| `violent_crimes`                  | Kejahatan dengan kekerasan.                                               |
| `sex_related_crimes`              | Kejahatan terkait seks.                                                   |
| `child_sexual_exploitation`       | Eksploitasi seksual anak.                                                 |
| `suicide_and_self_harm`           | Bunuh diri dan menyakiti diri sendiri.                                    |
| `indiscriminate_weapons`          | Senjata kimia, biologis, radiologis, nuklir, atau peledak.                |
| `intellectual_property`           | Pelanggaran hak cipta atau merek dagang.                                  |
| `defamation`                      | Penggambaran palsu yang kemungkinan merusak reputasi orang nyata.         |
| `non_violent_crimes`              | Kejahatan tanpa kekerasan.                                                |
| `hate`                            | Merendahkan seseorang karena karakteristik yang dilindungi.               |
| `privacy`                         | Informasi pribadi sensitif tentang seseorang.                             |
| `specialized_advice`              | Saran keuangan, medis, hukum, atau elektoral tanpa kualifikasi.           |
| `sexual_content`                  | Konten seksual eksplisit atau pornografi.                                 |
| `non_consensual_intimate_imagery` | Membuka pakaian, meniadakan pakaian, atau menseksualisasikan orang nyata. |
| `minor_coded_language`            | Bahasa yang mengisyaratkan subjek masih di bawah umur.                    |
| `real_person_likeness`            | Kemiripan dengan orang nyata yang dapat diidentifikasi dan memiliki nama. |
| `living_artist_style`             | Meniru gaya khas seniman tertentu yang masih hidup.                       |
| `prompt_injection`                | Upaya untuk mengesampingkan atau memanipulasi instruksi sistem.           |

## Menangani Error

Error mengembalikan body error standar Dodo Payments dengan `code` dan `message`. Tidak ada error yang merupakan keputusan, jadi tidak satu pun mengizinkan generasi:

| Status | `code`                       | Penyebab                                                                          | Tindakan                                                                  |
| ------ | ---------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `400`  | `INVALID_REQUEST_PARAMETERS` | Permintaan tidak valid, atau tidak memiliki `text` maupun `image`.                | Perbaiki permintaan.                                                      |
| `400`  | `MODERATION_INVALID_IMAGE`   | Gambar tidak dapat di-decode, berupa animasi, atau terlalu kecil.                 | Kirim gambar diam yang didukung.                                          |
| `403`  | `MODERATION_DISABLED`        | Dodo Payments telah menonaktifkan Moderation API untuk bisnis Anda.               | Hubungi dukungan untuk mengetahui alasannya.                              |
| `413`  | `MODERATION_INPUT_TOO_LARGE` | `text` melebihi 8.000 karakter, atau `image` melebihi batas ukuran.               | Persingkat teks atau perkecil gambar.                                     |
| `429`  | `MODERATION_OVERLOADED`      | Moderasi sedang mencapai kapasitas. Ini adalah batas throughput, bukan keputusan. | Tunggu selama beberapa detik sesuai header `Retry-After`, lalu coba lagi. |
| `503`  | `MODERATION_UNAVAILABLE`     | Tidak ada keputusan yang tersedia.                                                | Jangan membuat konten. Coba lagi nanti.                                   |

SDK secara default mencoba ulang `429` atau `503` sebanyak dua kali dan menunggu `Retry-After` di antara percobaan. Setelah percobaan ulang habis, SDK menghasilkan error, dan kode Anda harus memblokir permintaan.

## Menguji Integrasi Anda

Test mode mengembalikan keputusan mock dan tidak pernah memanggil model moderasi, sehingga Anda dapat menguji routing tanpa biaya. Kirim permintaan ke `https://test.dodopayments.com` dengan API key test mode.

Keputusan mock default adalah `allow`. Untuk mendapatkan hasil lain, letakkan salah satu string berikut di mana pun dalam `text`:

| String dalam `text`    | Respons                                               |
| ---------------------- | ----------------------------------------------------- |
| `dodo_mock_flag`       | `200` dengan `decision` ditetapkan ke `flag`          |
| `dodo_mock_deny`       | `200` dengan `decision` ditetapkan ke `deny`          |
| `dodo_mock_overloaded` | `429` `MODERATION_OVERLOADED` dengan `Retry-After: 1` |
| `dodo_mock_not_ready`  | `503` `MODERATION_UNAVAILABLE`                        |

Keputusan mock memuat catatan yang menyatakan bahwa keputusan tersebut adalah mock, dan semua skor kategorinya adalah `0`. Test mode menerapkan validasi permintaan yang sama seperti live mode. Untuk gambar, mode ini memeriksa encoding base64 dan format, tetapi tidak memeriksa jumlah frame atau dimensinya.

Sebelum mengaktifkan live mode, pastikan integrasi Anda menangani setiap kasus berikut:

<Steps>
  <Step title="Deny Blocks Generation">
    Kirim `dodo_mock_deny` dan pastikan model Anda tidak dipanggil.
  </Step>

  <Step title="Flag Follows Your Policy">
    Kirim `dodo_mock_flag` dan pastikan produk Anda melakukan hal yang ditetapkan kebijakan Anda.
  </Step>

  <Step title="Overload Retries">
    Kirim `dodo_mock_overloaded` dan pastikan kode Anda menunggu `Retry-After` serta tidak membuat konten tanpa keputusan.
  </Step>

  <Step title="An Outage Blocks Generation">
    Kirim `dodo_mock_not_ready` dan pastikan model Anda tidak dipanggil.
  </Step>

  <Step title="Every Generation Path Screens">
    Periksa bahwa setiap jalur kode yang mencapai model Anda terlebih dahulu memanggil Moderation API.
  </Step>
</Steps>

## Harga dan Penagihan

Moderation API dikenai biaya **\$0.30 USD per 1.000 screen yang dapat ditagihkan**. Tidak ada tier gratis dan tidak ada minimum.

Screen yang dapat ditagihkan adalah screen live mode yang mengembalikan keputusan. Screen berikut gratis dan tidak dihitung:

* Screen dalam test mode.
* Screen yang mengembalikan error, termasuk `429` dan `503`.

Dodo Payments menagih dalam blok penuh yang masing-masing terdiri dari 1.000 screen. Setiap blok penuh ditagihkan dalam waktu satu jam, dan screen yang belum memenuhi satu blok tidak ditagihkan sampai jumlahnya mencukupi. Biaya dipotong dari saldo USD Anda dan muncul di [ledger saldo](/api-reference/balance-ledger/list-ledger-entries) dengan tipe event `moderation_fees`. Payouts menampilkannya sebagai **Moderation Fees**.

### Melacak Penggunaan

Untuk melihat penggunaan Anda, panggil `GET /moderation/usage`. Respons mengembalikan:

| Field                   | Deskripsi                                                                                              |
| ----------------------- | ------------------------------------------------------------------------------------------------------ |
| `unbilled_screens`      | Screen yang dapat ditagihkan dan belum ditagihkan oleh Dodo Payments.                                  |
| `screens_to_next_block` | Jumlah screen yang dapat ditagihkan dan masih diperlukan untuk memenuhi blok 1.000 berikutnya.         |
| `daily`                 | Screen yang dapat ditagihkan per hari UTC selama 30 hari terakhir. Hari tanpa screen tidak disertakan. |

<CodeGroup>
  ```bash cURL theme={null}
  curl https://live.dodopayments.com/moderation/usage \
    -H "Authorization: Bearer $DODO_PAYMENTS_API_KEY"
  ```

  ```typescript Node.js theme={null}
  const usage = await client.moderation.retrieveUsage();
  console.log(usage.unbilled_screens, usage.screens_to_next_block);
  ```

  ```python Python theme={null}
  usage = client.moderation.retrieve_usage()
  print(usage.unbilled_screens, usage.screens_to_next_block)
  ```
</CodeGroup>

Test mode tidak mencatat screen, sehingga endpoint penggunaan tidak mengembalikan aktivitas test mode.

## Akses dan Privasi

Penyaringan memerlukan API key dengan akses write. API key apa pun, termasuk key read-only, dapat membaca penggunaan. Lihat [Authentication](/api-reference/introduction#authentication) untuk mengetahui cara membuat key dan menetapkan tingkat aksesnya.

Dodo Payments tidak menyimpan teks atau gambar yang Anda saring dan tidak menuliskannya ke log. Untuk setiap screen live mode, Dodo Payments menyimpan waktu, keputusan, dan `request_id` Anda untuk penagihan dan pelaporan penggunaan.

<CardGroup cols={2}>
  <Card title="Usage-Based Billing" icon="arrow-trend-up" href="/features/usage-based-billing/introduction">
    Tagih pelanggan Anda sendiri untuk setiap generasi.
  </Card>

  <Card title="Credit-Based Billing" icon="coins" href="/features/credit-based-billing">
    Jual kredit generasi dan potong kredit tersebut untuk setiap penggunaan.
  </Card>
</CardGroup>
