# Terima kejadian Stripe di endpoint webhook Anda

Dengarkan peristiwa dari akun Stripe pada endpoint webhook sehingga integrasi Anda dapat secara otomatis memicu reaksi.

Anda dapat membuat endpoint webhook HTTPS untuk menerima peristiwa. Setelah Anda mendaftarkan endpoint webhook, Stripe akan mendorong data real-time ke sana saat [peristiwa](https://docs.stripe.com/event-destinations.md#events-overview) terjadi di akun Stripe Anda. Stripe menggunakan HTTPS untuk mengirim peristiwa webhook ke aplikasi Anda sebagai muatan JSON yang mencakup informasi peristiwa.

Menerima peristiwa webhook membantu Anda merespons peristiwa asinkron, seperti ketika bank pelanggan mengonfirmasi pembayaran, pelanggan mengajukan sengketa atas tagihan, atau pembayaran rutin berhasil.

Anda juga dapat memakai peristiwa Stripe di infrastruktur AWS atau Azure dengan mengirim peristiwa secara langsung ke [Amazon EventBridge](https://docs.stripe.com/event-destinations/eventbridge.md) atau [Azure Event Grid](https://docs.stripe.com/event-destinations/eventgrid.md).

Selesaikan langkah di bawah ini untuk mulai menerima peristiwa webhook di aplikasi Anda. Anda dapat mendaftarkan dan membuat satu endpoint untuk menangani beberapa jenis peristiwa yang berbeda pada saat yang sama atau mengatur endpoint individual untuk peristiwa tertentu.

## Mengatur endpoint Anda

Gunakan [API](https://docs.stripe.com/api/v2/event-destinations.md) atau tab [Webhook](https://dashboard.stripe.com/webhooks) di Workbench untuk mendaftarkan URL yang dapat diakses endpoint webhook Anda sehingga Stripe tahu ke mana harus mengirimkan peristiwa. Anda dapat mendaftarkan hingga 16 endpoint webhook dengan Stripe. Endpoint webhook yang terdaftar harus berupa URL HTTPS yang dapat diakses publik.

- Jika Anda memiliki server localhost tetapi tidak memiliki URL HTTPS yang dapat diakses publik, Anda dapat menggunakan alat kanalisasi seperti [ngrok](https://ngrok.com/) untuk menghasilkan URL HTTPS sementara yang dapat diakses publik untuk digunakan demi keperluan pengujian.
- Secara bergantian, Anda dapat [menguji secara lokal menggunakan Stripe CLI](https://docs.stripe.com/webhooks.md#local-listener) sebelum mendaftarkan URL HTTPS yang dapat diakses secara publik.

### Format URL webhook

Format URL untuk mendaftarkan endpoint webhook adalah:

```
https://<your-website>/<your-webhook-endpoint>
```

Sebagai contoh, jika domain Anda `https://mycompanysite.com` dan rute ke endpoint webhook Anda `@app.route('/stripe_webhooks', methods=['POST'])`, tentukan `https://mycompanysite.com/stripe_webhooks` sebagai URL endpoint.

### Buat tujuan kejadian untuk endpoint webhook Anda

#### Dashboard

Untuk membuat endpoint webhook baru di Dashboard:

1. Buka tab [Webhook](https://dashboard.stripe.com/webhooks) di Workbench.
2. Klik **Buat tujuan peristiwa**.
3. Pilih **Akun Anda** untuk mendengarkan peristiwa dari akun Anda sendiri.
4. Pilih versi API untuk [objek peristiwa](https://docs.stripe.com/api/events.md) yang ingin Anda pakai.
5. Pilih [jenis peristiwa](https://docs.stripe.com/api/events/types.md) yang ingin Anda kirim ke endpoint webhook.
6. Pilih **Lanjutkan**, lalu pilih **Endpoint webhook** sebagai tipe tujuan.
7. Klik **Lanjutkan**, lalu berikan **URL endpoint** dan deskripsi opsional untuk webhook.
8. Di halaman pengaturan webhook, rahasia penandatanganan yang dimulai dengan `whsec_` muncul. Klik **Ungkap rahasia** dan salin nilainya untuk digunakan saat Anda [membuat penangan](https://docs.stripe.com/webhooks.md#webhook-endpoint-def).

> [Workbench](https://docs.stripe.com/workbench.md) menggantikan [Dashboard Pengembang](https://docs.stripe.com/development/dashboard.md) yang ada. Anda masih dapat [membuat endpoint webhook baru](https://docs.stripe.com/development/dashboard/webhooks.md) di Dashboard Pengembang, meskipun kami sarankan menggunakan Workbench.

#### API

Gunakan [/v2/core/event_destinations](https://docs.stripe.com/api/v2/event-destinations.md) endpoint untuk mendaftarkan endpoint baru.

#### Peristiwa snapshot

Untuk mendengarkan [peristiwa snapshot](https://docs.stripe.com/api/events/types.md) dari akun Anda sendiri, atur nilai [event_payload](https://docs.stripe.com/api/v2/core/event-destinations/create.md#v2_create_event_destinations-event_payload) ke `snapshot` dan nilai [enabled_events](https://docs.stripe.com/api/v2/core/event-destinations/create.md#v2_create_event_destinations-enabled_events) ke jenis peristiwa yang ingin Anda kirim ke endpoint webhook:

```curl
curl -X POST https://api.stripe.com/v2/core/event_destinations \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-08-26.preview" \
  --json '{
    "name": "My event destination",
    "type": "webhook_endpoint",
    "events_from": [
        "@self"
    ],
    "event_payload": "snapshot",
    "enabled_events": [
        "payment_intent.succeeded",
        "payment_intent.payment_failed"
    ],
    "webhook_endpoint": {
        "url": "https://mycompanysite.com/webhook"
    },
    "include": [
        "webhook_endpoint.signing_secret"
    ]
  }'
```

Output ini berisi nilai `webhook_endpoint.signing_secret` yang dimulai dengan `whsec_`. Salin nilai ini untuk digunakan saat Anda [membuat penangan](https://docs.stripe.com/webhooks.md#webhook-endpoint-def).

#### Peristiwa ringkas

Jika Anda menggunakan [peristiwa ringkas](https://docs.stripe.com/api/v2/core/events/event-types.md), Anda harus mendaftarkan endpoint webhook yang terpisah. Baca lebih lanjut tentang [perbedaan antara peristiwa ringkas dan snapshot](https://docs.stripe.com/event-destinations.md#events-overview).

Untuk mendengarkan [peristiwa ringkas](https://docs.stripe.com/api/v2/core/events/event-types.md) dari akun Anda sendiri, atur nilai [event_payload](https://docs.stripe.com/api/v2/core/event-destinations/create.md#v2_create_event_destinations-event_payload) ke `minor` dan nilai [enabled_events](https://docs.stripe.com/api/v2/core/event-destinations/create.md#v2_create_event_destinations-enabled_events) ke jenis peristiwa yang ingin Anda kirim ke endpoint webhook:

```curl
curl -X POST https://api.stripe.com/v2/core/event_destinations \
  -H "Authorization: Bearer <<YOUR_SECRET_KEY>>" \
  -H "Stripe-Version: 2026-08-26.preview" \
  --json '{
    "name": "My event destination",
    "type": "webhook_endpoint",
    "events_from": [
        "@self"
    ],
    "event_payload": "thin",
    "enabled_events": [
        "v1.billing.meter.error_report_triggered"
    ],
    "webhook_endpoint": {
        "url": "https://mycompanysite.com/webhook"
    },
    "include": [
        "webhook_endpoint.signing_secret"
    ]
  }'
```

Output ini berisi nilai `webhook_endpoint.signing_secret` yang dimulai dengan `whsec_`. Salin nilai ini untuk digunakan saat Anda [membuat penangan](https://docs.stripe.com/webhooks.md#webhook-endpoint-def).

### Uji secara lokal tanpa URL terdaftar

Jika Anda tidak memiliki URL HTTPS terdaftar yang dapat diakses secara publik, Anda dapat menguji webhook secara lokal dengan menggunakan Stripe CLI untuk [meneruskan peristiwa ke endpoint lokal Anda](https://docs.stripe.com/cli/use-cli#forward-events-to-your-local-webhook-endpoint):

1. Jika Anda belum melakukannya, [instal Stripe CLI](https://docs.stripe.com/cli/install) di mesin Anda.

2. Log masuk ke akun Stripe Anda dan atur CLI dengan menjalankan `stripe login` pada baris perintah.

3. Bolehkan host lokal Anda untuk menerima peristiwa simulasi dengan menjalankan [stripe listen](https://docs.stripe.com/cli/listen), bergantung pada cakupan dan jenis peristiwa:

   #### Teruskan kejadian snapshot

   Gunakan perintah berikut untuk meneruskan [peristiwa snapshot](https://docs.stripe.com/event-destinations.md#events-overview) dari akun Anda ke pendengar lokal Anda.

   ```bash
   stripe listen --forward-to localhost:4242/webhook
   ```

   #### Teruskan kejadian ringan

   Gunakan perintah berikut untuk meneruskan [peristiwa ringkas](https://docs.stripe.com/event-destinations.md#events-overview) dari akun Anda ke pendengar lokal Anda.

   ```bash
   stripe listen --forward-thin-to localhost:4242/webhook --thin-events "*"
   ```

   Perintah ini berasumsi bahwa Anda memiliki situs web localhost di port 4242 dengan endpoint `POST /webhook`, yang dapat dikonfigurasi saat Anda [membuat penangan](https://docs.stripe.com/webhooks.md#webhook-endpoint-def).

4. Perintah `stripe listen` menghasilkan `{{WEBHOOK_SIGNING_SECRET}}`. Salin nilai ini untuk digunakan saat Anda [membuat penangan](https://docs.stripe.com/webhooks.md#webhook-endpoint-def).

   ```output
   Ready! Your webhook signing secret is '{{WEBHOOK_SIGNING_SECRET}}' (^C to quit)
   ```

> Untuk menggunakan argumen `--forward-to` dengan `stripe listen`, Anda harus menjalankan perintah dengan [Stripe CLI](https://docs.stripe.com/cli.md) di terminal. Perintah ini tidak dapat dijalankan di [Workbench Shell](https://docs.stripe.com/workbench/shell.md) karena tidak mendukung argumen `--forward-to`.

## Buat handler

Siapkan fungsi endpoint HTTP atau HTTPS yang dapat menerima permintaan webhook dengan metode POST. Jika Anda masih mengembangkannya pada mesin lokal, fungsi endpoint dapat menggunakan HTTP. Setelah dapat diakses secara publik, fungsi endpoint webhook Anda harus menggunakan HTTPS.

Gunakan referensi Stripe API untuk mengidentifikasi [peristiwa ringkas](https://docs.stripe.com/api/v2/core/events/event-types.md) atau [objek kejadian cuplikan](https://docs.stripe.com/api/events/types.md) yang perlu diproses oleh handler webhook Anda.

Siapkan fungsi endpoint Anda sehingga fungsi tersebut:

- Menangani permintaan POST dengan muatan JSON yang menyertakan informasi peristiwa.
- Memverifikasi bahwa permintaan webhook dihasilkan oleh Stripe menggunakan muatan JSON, header `Stripe-Signature`, dan rahasia penandatanganan webhook `whsec_` dari langkah sebelumnya. Jika verifikasi gagal, Anda mendapatkan kesalahan.
- Dengan cepat mengembalikan kode status yang berhasil (`2xx`) sebelum ada logika kompleks yang dapat menyebabkan waktu habis. Misalnya, Anda harus mengembalikan respons `200` sebelum memperbarui Invoice pelanggan yang dibayarkan di sistem akuntansi Anda.

> #### Jangan memanipulasi permintaan bodi mentah
> 
> Stripe mewajibkan isi permintaan yang belum diproses untuk melakukan verifikasi tanda tangan. Jika Anda menggunakan framework, pastikan itu tidak memanipulasi isi permintaan yang belum diproses. Manipulasi apa pun pada  isi permintaan yang belum diproses akan menyebabkan verifikasi gagal.
> 
> Pelajari cara [memecahkan masalah kesalahan verifikasi tanda tangan](https://docs.stripe.com/webhooks/signature.md).

#### Contoh endpoint

Potongan kode ini adalah fungsi webhook yang dikonfigurasi untuk memeriksa kejadian yang diterima dari akun Stripe, menangani kejadian, dan mengembalikan tanggapan `200`. Referensikan handler kejadian [snapshot](https://docs.stripe.com/event-destinations.md#events-overview) saat Anda menggunakan sumber daya API v1, dan referensikan handler kejadian [tipis](https://docs.stripe.com/event-destinations.md#events-overview) saat Anda menggunakan sumber daya API v2.

#### Handler kejadian snapshot

Saat Anda membuat handler kejadian snapshot, gunakan definisi objek API pada saat kejadian untuk logika Anda dengan mengakses bidang `data.object` kejadian. Anda juga dapat mengambil sumber daya API dari API Stripe untuk mengakses definisi objek terbaru dan mutakhir.

#### Ruby

```ruby
require 'json'
require 'stripe'

client = Stripe::StripeClient.new(ENV.fetch('STRIPE_API_KEY'))

# Replace this endpoint secret with your unique endpoint secret key
# If you're testing with the CLI, run 'stripe listen' to find the secret key
# If you defined your endpoint using the API or the Dashboard, check your webhook settings for your endpoint secret: https://dashboard.stripe.com/webhooks
endpoint_secret = 'whsec_...';

# Using Sinatra
post '/webhook' do
  payload = request.body.read
  event = nil

  begin
    event = Stripe::Event.construct_from(
      JSON.parse(payload, symbolize_names: true)
    )
  rescue JSON::ParserError => e
    # Invalid payload
    status 400
    return
  end

  # Check that you have configured webhook signing
  if endpoint_secret
    # Retrieve the event by verifying the signature using the raw body and the endpoint secret
    signature = request.env['HTTP_STRIPE_SIGNATURE'];
    begin
      event = Stripe::Webhook.construct_event(
        payload, signature, endpoint_secret
      )
    rescue Stripe::SignatureVerificationError => e
      puts "⚠️  Webhook signature verification failed. #{e.message}"
      status 400
    end
  end

  # Handle the event
  case event.type
  when 'payment_intent.succeeded'
    payment_intent = event.data.object # contains a Stripe::PaymentIntent
    # Then define and call a method to handle the successful payment intent.
    # handle_payment_intent_succeeded(payment_intent)
  when 'payment_method.attached'
    payment_method = event.data.object # contains a Stripe::PaymentMethod
    # Then define and call a method to handle the successful attachment of a PaymentMethod.
    # handle_payment_method_attached(payment_method)
  # ... handle other event types
  else
    puts "Unhandled event type: #{event.type}"
  end

  status 200
end
```

#### Penangan peristiwa tipis (Clover+)

Saat Anda membuat penangan peristiwa tipis, gunakan metode `fetchRelatedObject()` untuk mengambil versi terbaru dari objek yang terkait dengan peristiwa. Peristiwa mungkin berisi [data tambahan](https://docs.stripe.com/event-destinations.md#fetch-data) yang hanya bisa Anda ambil melalui metode instance `.fetchEvent()` pada `EventNotification`. Bentuk pasti dari data tersebut bergantung pada `type` Peristiwa.

Tipe event harus tersedia pada saat rilis untuk menghasilkan kelas dalam versi SDK tersebut. Untuk menangani Event yang tidak memiliki kelas di SDK, gunakan kelas `UnknownEventNotification`.

#### Python

```python
import os
from stripe import StripeClient
from stripe.events import UnknownEventNotification

from flask import Flask, request, jsonify

app = Flask(__name__)
api_key = os.environ.get("STRIPE_API_KEY", "")
webhook_secret = os.environ.get("WEBHOOK_SECRET", "")

client = StripeClient(api_key)

@app.route("/webhook", methods=["POST"])
def webhook():
    webhook_body = request.data
    sig_header = request.headers.get("Stripe-Signature")

    try:
        event_notif = client.parse_event_notification(
            webhook_body, sig_header, webhook_secret
        )

        # type checkers will narrow the type based on the `type` property
        if event_notif.type == "v1.billing.meter.error_report_triggered":
            # in this block, event_notification is typed as
            # a V1BillingMeterErrorReportTriggeredEventNotification

            # there's basic info about the related object in the notification
            print(f"Meter w/ id {event_notif.related_object.id} had a problem")

            # or you can fetch the full object form the API for more details
            meter = event_notif.fetch_related_object()
            print(
                f"Meter {meter.display_name} ({meter.id}) had a problem"
            )

            # And you can always fetch the full event:
            event = event_notif.fetch_event()
            print(f"More info: {event.data.developer_message_summary}")

        elif event_notif.type == "v1.billing.meter.no_meter_found":
            # in this block, event_notification is typed as
            # a V1BillingMeterNoMeterFoundEventNotification

            # that class doesn't define `fetch_related_object` because the event
            # has no related object.
            # so this line would correctly give a type error:
            # meter = event_notif.fetch_related_object()

            # but fetching the event always works:
            event = event_notif.fetch_event()
            print(
                f"Err! No meter found: {event.data.developer_message_summary}"
            )

        # Events that were introduced after this SDK version release are
        # represented as `UnknownEventNotification`s.
        # They're valid, the SDK just doesn't have corresponding classes for them.
        # You must match on the "type" property instead.
        elif isinstance(event_notif, UnknownEventNotification):
            # these lines are optional, but will give you more accurate typing in this block
            from typing import cast

            event_notif = cast(UnknownEventNotification, event_notif)

            # continue matching on the type property
            # from this point on, the `related_object` property _may_ be None
            # (depending on the event type)
            if event_notif.type == "some.new.event":
                # if this event type has a related object, you can fetch it
                obj = event_notif.fetch_related_object()
                # otherwise, `obj` will just be `None`
                print(f"Related object: {obj}")

                # you can still fetch the full event, but it will be untyped
                event = event_notif.fetch_event()
                print(f"New event: {event.data}")  # type: ignore

        return jsonify(success=True), 200
    except Exception as e:
        return jsonify(error=str(e)), 400
```

## Coba handler Anda

Sebelum Anda menjadikan live fungsi endpoint webhook, sebaiknya Anda menguji integrasi aplikasi Anda dengan memicu peristiwa di Sandbox atau mengirim peristiwa pengujian dengan [Stripe CLI](https://docs.stripe.com/cli.md).

### Memicu peristiwa pengujian

Untuk mengirim kejadian percobaan, picu tipe kejadian yang menjadi langganan tujuan kejadian Anda dengan membuat objek secara manual di Dashboard Stripe. Pelajari cara memicu kejadian dengan [Stripe for VS Code](https://docs.stripe.com/stripe-vscode.md).

#### Picu kejadian potret

Anda dapat menggunakan perintah berikut, baik di [Stripe Shell](https://docs.stripe.com/workbench/shell.md) maupun [Stripe CLI](https://docs.stripe.com/cli.md). Contoh ini memicu peristiwa `payment_intent.succeeded`:

```bash
stripe trigger payment_intent.succeeded
Running fixture for: payment_intent
Trigger succeeded! Check dashboard for event details.
```

#### Picu kejadian tipis

Anda dapat menggunakan perintah berikut di [Stripe CLI](https://docs.stripe.com/cli.md). Contoh ini memicu peristiwa `v1.billing.meter.error_report_triggered`:

```bash
stripe trigger v1.billing.meter.error_report_triggered
Setting up fixture for: list_billing_meters
Running fixture for: list_billing_meters
Setting up fixture for: billing_meter
Running fixture for: billing_meter
Setting up fixture for: list_billing_meters_after_creation
Running fixture for: list_billing_meters_after_creation
Setting up fixture for: billing_meter_event_session
Running fixture for: billing_meter_event_session
Setting up fixture for: create_billing_meter_event_stream
Running fixture for: create_billing_meter_event_stream
Trigger succeeded! Check dashboard for event details.
```

## Optional: Buat tujuan peristiwa untuk Connect

Saat Anda [membuat tujuan peristiwa](https://docs.stripe.com/webhooks.md#create-webhook-endpoint) sebagai platform Connect, Anda memilih cakupan mana yang didengarkannya:

#### Dashboard

- **Akun Anda**: Peristiwa dari sumber daya dalam akun Anda.
- **Akun terhubung**: Peristiwa dari sumber daya milik akun terhubung Anda.

#### API

- [events_from=[“@self”]](https://docs.stripe.com/api/v2/core/event-destinations/create.md#v2_create_event_destinations-events_from): Peristiwa dari sumber daya dalam akun Anda.
- [events_from=[“@accounts”]](https://docs.stripe.com/api/v2/core/event-destinations/create.md#v2_create_event_destinations-events_from): Peristiwa dari sumber daya milik akun terhubung Anda.

Mendaftarkan tujuan peristiwa untuk **Akun terhubung** demi menerima peristiwa untuk sumber daya milik akun terhubung Anda. Contoh mencakup [Direct Charges](https://docs.stripe.com/connect/direct-charges.md), Pelanggan dan metode pembayaran dari akun terhubung, kegagalan Payout, dan pembaruan siklus hidup akun terhubung snapshot lama, seperti onboarding, verifikasi, perubahan akun eksternal, dan pemutusan sambungan akun. Untuk Objek akun v2, cakupan ini hanya menerima peristiwa snapshot untuk Objek akun yang mewakili akun terhubung Anda.

Tergantung pada integrasi Connect Anda, Anda mungkin juga perlu mendaftarkan tujuan peristiwa untuk **Akun Anda**. Alasannya mencakup:

- Memproses peristiwa untuk sumber daya dalam akun platform Anda, termasuk Pelanggan platform, charge milik platform, [Destination Charges](https://docs.stripe.com/connect/destination-charges.md), dan [Separate Charges and Transfers](https://docs.stripe.com/connect/separate-charges-and-transfers.md).
- Memproses peristiwa ringkas yang terkait dengan Objek akun v2 yang mewakili akun terhubung.

Lihat [webhook Connect](https://docs.stripe.com/connect/webhooks.md?accounts-namespace=v2) untuk detail selengkapnya.

### Uji Connect secara lokal tanpa URL terdaftar

#### Peristiwa snapshot

Gunakan perintah berikut untuk meneruskan [peristiwa snapshot](https://docs.stripe.com/event-destinations.md#events-overview) dari akun terhubung ke pendengar lokal Anda.

```bash
stripe listen --forward-connect-to localhost:4242/webhook
```

#### Peristiwa ringkas

Gunakan perintah berikut untuk meneruskan [peristiwa ringkas](https://docs.stripe.com/event-destinations.md#events-overview) dari akun terhubung ke pendengar lokal Anda.

```bash
stripe listen --forward-thin-connect-to localhost:4242/webhook --thin-events "*"
```

## Optional: Buat tujuan peristiwa untuk organisasi

Saat Anda [membuat tujuan peristiwa](https://docs.stripe.com/webhooks.md#create-webhook-endpoint) sebagai organisasi, Anda memilih ruang lingkup mana yang akan didengarkannya:

#### Dashboard

- **Akun di organisasi Anda**: Peristiwa dari sumber daya di akun organisasi Anda.
- **Akun terhubung**: Peristiwa dari sumber daya di dalam akun terhubung organisasi Anda.

#### API

- [events_from=[“@organization_members”]](https://docs.stripe.com/api/v2/core/event-destinations/create.md#v2_create_event_destinations-events_from): Peristiwa dari sumber daya di akun organisasi Anda.
- [events_from=[“@organization_members/@accounts”]](https://docs.stripe.com/api/v2/core/event-destinations/create.md#v2_create_event_destinations-events_from): Peristiwa dari sumber daya di dalam akun terhubung organisasi Anda.

### Perilaku tipe kejadian yang tidak didukung untuk tujuan kejadian organisasi

Stripe mengirimkan sebagian besar jenis peristiwa secara asinkron, tetapi menunggu respons untuk beberapa jenis peristiwa. Dalam kasus ini, perilaku Stripe berbeda berdasarkan apakah tujuan peristiwa merespons.

Jika tujuan acara Anda menerima peristiwa [Organisasi](https://docs.stripe.com/get-started/account/orgs.md), peristiwa yang memerlukan respons memiliki batasan berikut:

- Anda tidak dapat berlangganan `issuing_authorization.request` untuk tujuan organisasi. Sebagai gantinya, siapkan [endpoint webhook](https://docs.stripe.com/webhooks.md#example-endpoint) di akun Stripe dalam organisasi untuk berlangganan tipe kejadian ini. Gunakan `issuing_authorization.request` untuk mengotorisasi permintaan pembelian secara real-time.
- Tujuan organisasi menerima `checkout_sessions.completed` tidak dapat [menangani perilaku pengalihan](https://docs.stripe.com/checkout/fulfillment.md#redirect-hosted-checkout) saat Anda menyematkan [Checkout](https://docs.stripe.com/payments/checkout.md) langsung di situs web Anda atau mengarahkan pelanggan ke halaman pembayaran yang di-hosting Stripe. Untuk memengaruhi perilaku pengalihan Checkout, proses jenis peristiwa ini dengan [webhook endpoint](https://docs.stripe.com/webhooks.md#example-endpoint) yang dikonfigurasi di akun Stripe dalam organisasi.
- Tujuan organisasi yang merespons dengan gagal terhadap peristiwa `invoice.created` tidak dapat memengaruhi[ finalisasi invoice otomatis saat menggunakan penagihan otomatis](https://docs.stripe.com/billing/subscriptions/webhooks.md#understand). Anda harus memproses jenis peristiwa ini dengan [endpoint webhook](https://docs.stripe.com/webhooks.md#example-endpoint) yang dikonfigurasi di akun Stripe dalam organisasi untuk memicu finalisasi invoice otomatis.

#### Menggunakan `context`

#### Peristiwa snapshot

Potongan kode ini adalah fungsi webhook yang dikonfigurasi untuk memeriksa kejadian yang diterima, mendeteksi akun asal jika berlaku, menangani kejadian, dan mengembalikan respons `200`.

#### Ruby

```ruby
require 'json'

client = Stripe::StripeClient.new('sk_...')

# Using Sinatra
post '/webhook' do
  payload = request.body.read
  event = nil

  begin
    event = Stripe::Event.construct_from(
      JSON.parse(payload, symbolize_names: true)
    )
  rescue JSON::ParserError => e
    # Invalid payload
    status 400
    return
  end

  # Extract the context
  context = event.context

  # Define your API key variables (ideally loaded securely)
  ACCOUNT_123_API_KEY = "sk_test_123"
  ACCOUNT_456_API_KEY = "sk_test_456"

  account_api_keys = {
    "account_123" => ACCOUNT_123_API_KEY,
    "account_456" => ACCOUNT_456_API_KEY
  }

  api_key = account_api_keys[context]

  if api_key.nil?
    puts "No API key found for context: #{context}"
    status 400
    return
  end

  # Handle the event
  case event.type
  when 'customer.created'
    customer = event.data.object

    begin

      latest_customer = client.v1.customers.retrieve(customer.id, {api_key: api_key})
      handle_customer_created(latest_customer, context)
    rescue => e
      puts "Error retrieving customer: #{e.message}"
      status 500
      return
    end

  when 'payment_method.attached'
    payment_method = event.data.object

    begin
      latest_payment_method = client.v1.payment_methods.retrieve(payment_method.id, {api_key: api_key})
      handle_payment_method_attached(latest_payment_method, context)
    rescue => e
      puts "Error retrieving payment method: #{e.message}"
      status 500
      return
    end

  else
    puts "Unhandled event type: #{event.type}"
  end

  status 200
end
```

#### Penangan peristiwa tipis (Clover+)

Gunakan properti `context` `EventNotification` untuk mengidentifikasi akun untuk peristiwa dalam [organisasi](https://docs.stripe.com/get-started/account/orgs.md) Anda. Anda harus mengatur [tajuk Stripe-Context](https://docs.stripe.com/context.md) secara manual untuk semua panggilan API kecuali `.fetchRelatedObject()` dan `.fetchEvent()`, yang melakukan ini untuk Anda secara otomatis.

#### Python

```python
org_api_key = os.environ.get("STRIPE_API_KEY")
webhook_secret = os.environ.get("WEBHOOK_SECRET")
client = StripeClient(org_api_key)

# inside your webhook handler
event_notification = client.parse_event_notification(payload, sig_header, webhook_secret)

# uses `context` automatically
event_notification.fetch_event()

# pass context manually for other API requests
client.v1.invoices.list(stripe_context=event_notification.context)
```

## Debug integrasi webhook

Beberapa tipe masalah dapat terjadi ketika mengirimkan kejadian ke endpoint webhook Anda:

- Stripe mungkin tidak dapat mengirimkan kejadian ke endpoint webhook Anda.
- Endpoint webhook Anda mungkin memiliki masalah SSL.
- Konektivitas jaringan Anda terputus-putus.
- Endpoint webhook Anda tidak menerima kejadian yang Anda perkirakan.

### Lihat pengiriman kejadian

Untuk melihat pengiriman peristiwa, buka [Workbench](https://docs.stripe.com/workbench.md), pilih endpoint webhook di bawah **Webhooks**, lalu pilih tab **Event deliveries**. Tab **Event deliveries** menyediakan daftar peristiwa beserta statusnya, apakah `Terkirim`, `Tertunda`, atau `Gagal`. Klik pada sebuah peristiwa untuk melihat metadata, termasuk kode status HTTP dari upaya pengiriman dan waktu pengiriman mendatang yang masih tertunda.

Anda juga dapat menggunakan [Stripe CLI](https://docs.stripe.com/cli.md) untuk [mendengarkan peristiwa](https://docs.stripe.com/webhooks.md#test-webhook) secara langsung di terminal Anda.

### Perbaiki kode status HTTP

Bila kejadian menampilkan kode status `200`, ini menunjukkan pengiriman yang berhasil ke endpoint webhook. Anda mungkin juga menerima kode status selain `200`. Lihat tabel di bawah ini untuk daftar kode status HTTP yang umum dan solusi yang direkomendasikan.

| Status webhook menunggu | Keterangan | Perbaiki |
| --- | --- | --- |
| (Tidak dapat menghubungkan) ERR | Kami tidak dapat membuat koneksi ke server tujuan. | Pastikan domain host Anda dapat diakses secara publik dengan internet. |
| (`302`) ERR (atau status `3xx` lainnya) | Server tujuan berusaha mengarahkan permintaan ke lokasi lain. Kami menganggap respons pengalihan ke permintaan webhook sebagai kegagalan. | Atur tujuan endpoint webhook ke URL yang diselesaikan dengan pengalihan. |
| (`400`) ERR (atau status `4xx` lainnya) | Server tujuan tidak dapat atau tidak akan memproses permintaan tersebut. Hal ini mungkin terjadi saat server mendeteksi kesalahan (`400`), saat URL tujuan memiliki batasan akses (`401`, `403`, `405`), atau saat URL tujuan tidak ditemukan (`404`). | Pastikan endpoint Anda dapat diakses publik ke internet dan menerima metode HTTP POST. |
| (`500`) ERR (atau status `5xx` lainnya) | Server tujuan mengalami kesalahan saat memproses permintaan. | Tinjau log aplikasi Anda untuk memahami alasannya menampilkan kesalahan `500`. |
| (Kesalahan TLS) ERR | Kami tidak dapat membuat koneksi yang aman ke server tujuan. Masalah dengan sertifikat SSL/TLS atau sertifikat perantara dalam rantai sertifikat server tujuan biasanya menyebabkan kesalahan ini. Stripe memerlukan *TLS* (TLS refers to the process of securely transmitting data between the client—the app or browser that your customer is using—and your server. This was originally performed using the SSL (Secure Sockets Layer) protocol) versi `v1.2` atau yang lebih tinggi. | Lakukan [percobaan server SSL](https://www.ssllabs.com/ssltest/) untuk menemukan masalah yang mungkin menyebabkan kesalahan ini. |
| (Waktu habis) ERR | Server tujuan memerlukan waktu terlalu lama untuk menanggapi permintaan webhook. | Pastikan Anda segera menunda logika kompleks dan mengembalikan tanggapan yang berhasil dalam kode penanganan webhook Anda. |

## Perilaku pengiriman kejadian

Bagian ini membantu Anda memahami berbagai perilaku yang diperkirakan mengenai cara Stripe mengirim kejadian ke endpoint webhook Anda.

### Percobaan ulang otomatis

Stripe mencoba untuk mengirim kejadian ke tujuan Anda hingga selama tiga hari dengan backoff eksponensial dalam mode live. Lihat kapan percobaan ulang berikutnya akan terjadi, jika berlaku, di tab **Pengiriman kejadian** dari tujuan kejadian. Kami mencoba ulang pengiriman kejadian yang dibuat di sandbox tiga kali selama beberapa jam. Jika tujuan Anda telah dinonaktifkan atau dihapus saat kami mencoba ulang, kami mencegah percobaan ulang mendatang dari kejadian tersebut. Namun, jika Anda menonaktifkan, kemudian mengaktifkan ulang tujuan kejadian sebelum kami dapat mencoba ulang, Anda masih melihat upaya percobaan ulang mendatang.

### Percobaan ulang manual

Ada dua cara untuk mencoba ulang kejadian secara manual:

- Di Dashboard Stripe, klik **Kirim ulang** saat melihat acara tertentu. Ini berfungsi hingga 15 hari setelah pembuatan acara.
- Dengan [Stripe CLI](https://docs.stripe.com/cli/events/resend), jalankan perintah `stripe events resend <event_id> --webhook-endpoint=<endpoint_id>`. Ini berfungsi hingga 30 hari setelah pembuatan acara.

Mengirim ulang peristiwa yang mengalami kegagalan pengiriman sebelumnya secara manual ke endpoint webhook tidak mengabaikan [perilaku percobaan ulang otomatis](https://docs.stripe.com/webhooks.md#automatic-retries) Stripe, bahkan jika hal itu menghasilkan kode status `2xx`. Pelajari cara [memproses peristiwa webhook yang tidak terkirim](https://docs.stripe.com/webhooks/process-undelivered-events.md) untuk menghentikan percobaan ulang di masa mendatang.

### Pengurutan kejadian

Stripe tidak menjamin pengiriman kejadian sesuai dengan urutan pembuatannya. Misalnya, pembuatan langganan dapat menghasilkan kejadian berikut ini:

- `customer.subscription.created`
- `invoice.created`
- `invoice.paid`
- `charge.created` (jika ada charge)

Pastikan destinasi peristiwa Anda tidak bergantung pada urutan penerimaan peristiwa. Peristiwa snapshot mencatat `created` dalam hitungan detik, sehingga beberapa peristiwa berbeda dapat memiliki stempel waktu yang sama. Jangan gunakan `created` untuk menentukan urutan peristiwa atau memastikan apakah Anda sudah memproses suatu peristiwa. Sebagai gantinya, lacak [ID peristiwa](https://docs.stripe.com/api/events/object.md#event_object-id) untuk mengidentifikasi pengiriman duplikat. Anda juga dapat menggunakan API untuk mengambil objek yang hilang. Misalnya, Anda dapat mengambil objek invoice, charge, dan langganan menggunakan informasi dari `invoice.paid` jika Anda menerima peristiwa ini terlebih dahulu.

### Pembuatan versi API

Versi API di pengaturan akun Anda saat kejadian berlangsung menentukan versi API, sehingga struktur [Kejadian](https://docs.stripe.com/api/events.md) dikirim ke tujuan Anda. Misalnya, jika akun diatur ke versi API yang lebih lama, seperti 16-02-2015, dan Anda mengubah versi API untuk permintaan spesifik dengan [pembuatan versi](https://docs.stripe.com/api.md#versioning), objek [Event](https://docs.stripe.com/api/events.md) yang dihasilkan serta dikirim ke tujuan Anda tetap didasarkan pada versi API 2015-02-16. Anda tidak dapat mengubah objek [Kejadian](https://docs.stripe.com/api/events.md) setelah pembuatan. Misalnya, jika Anda memperbarui charge, kejadian charge semula tetap tidak berubah. Akibatnya, pembaruan selanjutnya pada versi API akun Anda tidak secara retroaktif mengubah objek [Kejadian](https://docs.stripe.com/api/events.md) yang ada. Mengambil [Kejadian](https://docs.stripe.com/api/events.md) yang lebih lama dengan memanggil `/v1/events` menggunakan versi API yang lebih baru juga tidak memengaruhi struktur kejadian yang diterima. Anda dapat mengatur tujuan kejadian percobaan ke versi API default ataupun versi API terbaru. [Kejadian](https://docs.stripe.com/api/events.md) yang dikirim ke tujuan disusun untuk versi yang ditentukan tujuan kejadian.

## Praktik terbaik menggunakan webhook

Tinjau praktik terbaik ini untuk memastikan endpoint webhook tetap aman dan berfungsi dengan baik bersama integrasi Anda.

### Tangani kejadian duplikat

Terkadang endpoint webhook dapat menerima kejadian yang sama lebih dari satu kali. Anda dapat berhati-hati terhadap resi kejadian yang diduplikasi dengan memasukkan [identifikasi kejadian](https://docs.stripe.com/api/events/object.md#event_object-id) yang telah Anda proses, kemudian tidak memproses kejadian yang sudah dimasukkan.

Dalam beberapa kasus, dua objek Event yang terpisah dihasilkan dan dikirim. Untuk mengidentifikasi duplikat tersebut, gunakan ID objek di `data.object` bersama dengan `event.type`.

### Hanya dengarkan tipe kejadian yang diperlukan oleh integrasi Anda

Konfigurasikan endpoint webhook untuk hanya menerima tipe kejadian yang diperlukan oleh integrasi Anda. Mendengarkan kejadian ekstra (atau semua kejadian) akan membebani server Anda dan kami tidak merekomendasikannya.

Anda dapat [mengubah kejadian](https://docs.stripe.com/api/webhook_endpoints/update.md#update_webhook_endpoint-enabled_events) yang diterima oleh endpoint webhook di Dashboard atau dengan API.

### Tangani kejadian secara asinkron

Konfigurasikan handler Anda untuk memproses kejadian masuk dengan antrean asinkron. Anda mungkin mengalami masalah skalabilitas jika memilih untuk memproses kejadian secara sinkron. Setiap lonjakan besar dalam pengiriman webhook (misalnya, selama awal bulan ketika semua langganan diperbarui) dapat membanjiri host endpoint Anda.

Antrean asinkron memungkinkan Anda memproses kejadian bersamaan dengan kecepatan yang dapat didukung sistem Anda.

### Bebaskan rute webhook dari proteksi CSRF

Jika menggunakan Rails, Django, atau kerangka web lain, situs Anda dapat memeriksa secara otomatis apakah setiap permintaan POST berisi *CSRF token*. Ini adalah fitur keamanan penting yang membantu memproteksi Anda dan pengguna Anda dari upaya [cross-site request forgery](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_\(CSRF\)). Namun, langkah pengamanan ini juga dapat mencegah situs Anda memproses kejadian yang sah. Jika demikian, Anda mungkin perlu mengecualikan rute webhook dari proteksi CSRF.

#### Rails

```ruby
class StripeController < ApplicationController
  # If your controller accepts requests other than Stripe webhooks,
  # you'll probably want to use `protect_from_forgery` to add CSRF
  # protection for your application. But don't forget to exempt
  # your webhook route!
  protect_from_forgery except: :webhook

  def webhook
    # Process webhook data in `params`
  end
end
```

### Terima kejadian dengan server HTTPS

Jika Anda menggunakan URL HTTPS untuk endpoint webhook (diperlukan dalam mode live), Stripe akan memvalidasi keamanan sambungan ke server Anda sebelum mengirim data webhook. Agar hal ini berfungsi, server Anda harus dikonfigurasi dengan benar untuk mendukung HTTPS dengan sertifikat server yang valid. Webhook Stripe hanya mendukung *TLS* (TLS refers to the process of securely transmitting data between the client—the app or browser that your customer is using—and your server. This was originally performed using the SSL (Secure Sockets Layer) protocol) versi v1.2 dan v1.3.

### Cabut rahasia penandatanganan endpoint secara berkala

Rahasia yang digunakan untuk memverifikasi bahwa peristiwa berasal dari Stripe dapat diubah di tab [Webhook](https://dashboard.stripe.com/webhooks) di Workbench. Untuk menjaganya tetap aman, kami menyarankan agar Anda secara berkala merotasi rahasia, atau saat Anda mencurigai rahasia telah disusupi.

Untuk mencabut rahasia:

1. Klik setiap endpoint di tab [Webhook](https://dashboard.stripe.com/webhooks) Workbench yang Anda inginkan untuk merotasi rahasianya.
2. Masuk ke menu perluasan (⋯) dan klik **Cabut rahasia**. Anda dapat memilih untuk segera mengakhiri rahasia saat ini atau menunda kedaluwarsanya hingga 24 jam agar Anda memiliki waktu untuk memperbarui kode verifikasi di server Anda. Selama waktu ini, beberapa rahasia aktif bagi endpoint. Stripe membuat satu tanda tangan per rahasia hingga kedaluwarsa.

### Verifikasikan kejadian dikirim dari Stripe

Tanpa verifikasi, penyerang dapat mengirim peristiwa webhook palsu ke endpoint Anda untuk memicu tindakan seperti memenuhi pesanan, memberikan akses akun, atau memodifikasi catatan. Selalu verifikasi bahwa peristiwa webhook berasal dari Stripe sebelum menindaklanjutinya.

Gunakan kedua perlindungan ini:

- **Daftar IP yang diizinkan**: Stripe mengirimkan peristiwa webhook dari daftar yang ditetapkan [alamat IP](https://docs.stripe.com/ips.md). Konfigurasikan server atau firewall Anda untuk hanya menerima permintaan webhook dari alamat ini.
- **Verifikasi tanda tangan**: Stripe menandatangani setiap peristiwa webhook dengan menyertakan tanda tangan di header `Stripe-Signature`. Verifikasi tanda tangan ini menggunakan [pustaka resmi](https://docs.stripe.com/webhooks.md#verify-signature) kami atau ikuti [langkah-langkah verifikasi manual](https://docs.stripe.com/webhooks.md?verify=verify-manually#verify-signature) untuk mengonfirmasi bahwa peristiwa tersebut tidak dikirim atau dimodifikasi oleh pihak ketiga.

Bagian berikut menerangkan cara memverifikasi tanda tangan webhook:

1. Ambil rahasia endpoint Anda.
2. Verifikasikan tanda tangan.

#### Mengambil rahasia endpoint Anda

Gunakan Workbench dan buka tab [Webhook](https://dashboard.stripe.com/webhooks) untuk melihat semua endpoint Anda. Pilih endpoint tempat Anda ingin mendapatkan rahasianya, lalu klik **Klik untuk menampilkan**.

Stripe membuatkan kunci rahasia yang unik bagi setiap endpoint. Jika Anda menggunakan endpoint yang sama untuk [kunci API percobaan maupun live](https://docs.stripe.com/keys.md#test-live-modes), rahasia untuk setiap kunci itu berbeda. Selain itu, jika menggunakan beberapa endpoint, Anda harus memperoleh rahasia untuk setiap kunci yang tanda tangannya ingin Anda verifikasi. Setelah persiapan ini, Stripe mulai menandatangani setiap webhook yang dikirim ke endpoint.

#### Verifikasikan tanda tangan.

#### Verifikasikan dengan pustaka resmi (direkomendasikan)

### Verifikasikan tanda tangan webhook dengan pustaka resmi

Kami merekomendasikan penggunaan pustaka resmi kami untuk memverifikasi tanda tangan. Anda melakukan verifikasi dengan memberikan payload kejadian, header `Stripe-Signature` dan rahasia endpoint. Jika verifikasi gagal, Anda akan menerima kesalahan.

Jika Anda mendapatkan kesalahan verifikasi tanda tangan, baca panduan kami tentang [pemecahan masalahnya](https://docs.stripe.com/webhooks/signature.md).

> Stripe mewajibkan isi permintaan yang belum diproses untuk melakukan verifikasi tanda tangan. Jika Anda menggunakan framework, pastikan itu tidak memanipulasi isi permintaan yang belum diproses. Manipulasi apa pun pada  isi permintaan yang belum diproses akan menyebabkan verifikasi gagal.

#### Ruby

```ruby

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

require 'stripe'
require 'sinatra'

# If you are testing your webhook locally with the Stripe CLI you
# can find the endpoint's secret by running `stripe listen`
# Otherwise, find your endpoint's secret in your webhook settings in
# the Developer Dashboard
endpoint_secret = 'whsec_...'

# Using the Sinatra framework
set :port, 4242

post '/my/webhook/url' do
  payload = request.body.read
  sig_header = request.env['HTTP_STRIPE_SIGNATURE']
  event = nil

  begin
    event = Stripe::Webhook.construct_event(
      payload, sig_header, endpoint_secret
    )
  rescue JSON::ParserError => e
    # Invalid payload
    puts "Error parsing payload: #{e.message}"
    status 400
    return
  rescue Stripe::SignatureVerificationError => e
    # Invalid signature
    puts "Error verifying webhook signature: #{e.message}"
    status 400
    return
  end

  # Handle the event
  case event.type
  when 'payment_intent.succeeded'
    payment_intent = event.data.object # contains a Stripe::PaymentIntent
    puts 'PaymentIntent was successful!'
  when 'payment_method.attached'
    payment_method = event.data.object # contains a Stripe::PaymentMethod
    puts 'PaymentMethod was attached to a Customer!'
  # ... handle other event types
  else
    puts "Unhandled event type: #{event.type}"
  end

  status 200
end
```

#### Verifikasikan secara manual

### Verifikasikan tanda tangan webhook secara manual

Meski kami merekomendasikan Anda menggunakan pustaka resmi kami untuk memverifikasi tanda tangan kejadian webhook, Anda dapat membuat solusi custom dengan mengikuti bagian ini.

Header `Stripe-Signature` yang disertakan di setiap kejadian yang ditandatangani berisi stempel waktu dan satu atau beberapa tanda tangan yang harus Anda verifikasi. Stempel waktu memiliki awalan `t=`, dan setiap tanda tangan memiliki awalan *scheme*. Skema dimulai dengan `v`, diikuti oleh bilangan bulat. Saat ini, satu-satunya skema tanda tangan live yang valid adalah `v1`. Untuk membantu percobaan, Stripe mengirim tanda tangan tambahan dengan skema `v0` palsu, untuk kejadian percobaan.

```
Stripe-Signature:
t=1492774577,
v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd,
v0=6ffbb59b2300aae63f272406069a9788598b792a944a07aba816edb039989a39
```

> Kami menyediakan baris baru untuk kejelasan, tetapi header `Stripe-Signature` yang sebenarnya ada di satu baris.

Stripe membuat tanda tangan menggunakan kode autentikasi pesan berbasis hash ([HMAC](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code)) dengan [SHA-256](https://en.wikipedia.org/wiki/SHA-2). Untuk mencegah [serangan downgrade](https://en.wikipedia.org/wiki/Downgrade_attack), abaikan semua skema yang bukan `v1`.

Anda dapat memiliki beberapa tanda tangan dengan pasangan skema-rahasia yang sama bila Anda [mencabut rahasia endpoint](https://docs.stripe.com/webhooks.md#roll-endpoint-secrets), serta tetap mengaktifkan rahasia sebelumnya hingga 24 jam. Selama waktu ini, endpoint Anda memiliki beberapa rahasia aktif dan Stripe membuatkan satu tanda tangan untuk setiap rahasia.

Untuk membuat solusi manual guna memverifikasi tanda tangan, Anda harus menyelesaikan langkah-langkah berikut:

#### Langkah 1: Ekstrak stempel waktu dan tanda tangan dari tajuk

Pisahkan tajuk menggunakan karakter `,` sebagai pemisah untuk mendapatkan daftar elemen. Kemudian pisahkan setiap elemen menggunakan karakter `=` sebagai pemisah untuk mendapatkan awalan dan pasangan nilai.

Nilai untuk awalan `t` sesuai dengan stempel waktu, dan `v1` sesuai dengan tanda tangan. Anda dapat membuang semua elemen lain.

#### Langkah 2: Siapkan string `signed_payload`

String `signed_payload` dibuat dengan penggabungan:

- Stempel waktu (sebagai string)
- Karakter `.`
- Payload JSON aktual (yaitu, isi permintaan)

#### Langkah 3: Tentukan perkiraan tanda tangan

Hitung HMAC dengan fungsi hash SHA256. Gunakan rahasia penandatanganan endpoint sebagai kunci, dan gunakan string `signed_payload` sebagai pesan.

#### Langkah 4: Bandingkan tanda tangan

Bandingkan tanda tangan di tajuk dengan perkiraan tanda tangan. Untuk pencocokan kesetaraan, hitung perbedaan antara stempel waktu saat ini dan stempel waktu yang diterima, kemudian putuskan apakah perbedaannya masih dalam toleransi Anda.

Untuk memproteksi dari timing attack, gunakan perbandingan string berwaktu konstan untuk membandingkan perkiraan tanda tangan dengan setiap tanda tangan yang diterima.

### Mencegah replay attack

[Serangan replay](https://en.wikipedia.org/wiki/Replay_attack) adalah saat penyerang mencegat payload yang valid dan tanda tangannya, kemudian mengirimkannya kembali. Untuk melakukan mitigasi serangan semacam itu, Stripe menyertakan stempel waktu di tajuk `Stripe-Signature`. Karena merupakan bagian dari payload yang ditandatangani, stempel waktu ini juga diverifikasi oleh tanda tangan, sehingga penyerang tidak dapat mengubah stempel waktu tanpa membatalkan tanda tangan. Jika tanda tangan valid tetapi stempel waktu terlalu lama, aplikasi Anda dapat menolak payload.

Pustaka kami memiliki toleransi default 5 menit antara stempel waktu dan waktu saat ini. Anda dapat mengubah toleransi ini dengan memberikan parameter tambahan ketika memverifikasi tanda tangan. Gunakan Network Time Protocol ([NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol)) untuk memastikan jam server Anda akurat dan sinkron dengan waktu pada server Stripe.

> Jangan gunakan nilai toleransi `0`. Menggunakan nilai toleransi `0` menonaktifkan pemeriksaan kebaruan sepenuhnya.

Stripe membuat stempel waktu dan tanda tangan setiap kali kami mengirim kejadian ke endpoint Anda. Jika Stripe mencoba ulang kejadian (misalnya endpoint Anda yang sebelumnya dibalas dengan kode status non-`2xx`), maka kami akan membuat tanda tangan dan stempel waktu baru untuk upaya pengiriman baru.

### Segera mengembalikan tanggapan 2xx

[endpoint](https://docs.stripe.com/webhooks.md#example-endpoint) Anda harus dengan cepat mengembalikan kode status yang berhasil (`2xx`) sebelum logika rumit apa pun yang dapat menyebabkan batas waktu habis. Misalnya, Anda harus mengembalikan respons `200` sebelum memperbarui Invoice pelanggan sebagai lunas di sistem akuntansi Anda.

## See also

- [Kirim kejadian ke Amazon EventBridge](https://docs.stripe.com/event-destinations/eventbridge.md)
- [Mengirim peristiwa ke Azure Event Grid](https://docs.stripe.com/event-destinations/eventgrid.md)
- [Daftar tipe kejadian ringkas](https://docs.stripe.com/api/v2/core/events/event-types.md)
- [Daftar jenis kejadian snapshot](https://docs.stripe.com/api/events/.md)
- [Pembangun endpoint webhook interaktif](https://docs.stripe.com/webhooks/quickstart.md)
