Skip to content

Idempotency (Duplication Prevention)

Network errors can happen at any time. A client might send a POST /v1/payments/create request, but the internet connection drops before the server can respond. In this situation, the client doesn't know if the charge was successfully created or not.

If the client repeats (retries) the exact same request, there is a risk of creating two duplicate charges for the same order.

To prevent this issue, Gerbang Pay implements an Idempotency mechanism.

How Idempotency Works

The POST /v1/payments/create endpoint requires you to send an HTTP Header named X-Idempotency-Key.

This key is a unique string that you generate yourself. The best practice is to use your application's internal Order ID or shopping cart ID (maximum 255 characters).

http
X-Idempotency-Key: order-abc-12345

When Gerbang Pay receives a request:

  1. The system checks if this X-Idempotency-Key has been received in the last 24 hours.
  2. New Key: If it hasn't been received before, Gerbang Pay processes it normally as a new transaction.
  3. Same Key, Same Payload: If the key has already been processed and its JSON request body is exactly the same as the previous one, Gerbang Pay will ignore the new request and immediately return the exact same original JSON response as the first request (with a 200 OK status). This makes the retry process 100% safe.
  4. Same Key, Different Payload: If the key already exists but the request content (e.g., amount or method_type) is different from the original, the system will immediately reject it. The client will receive an HTTP 409 Conflict status with an IDEMPOTENCY_CONFLICT error.

Time to Live (TTL)

The idempotency cache is stored in our in-memory system (Valkey) with a TTL (Time-To-Live) of 24 Hours.

This means if you send a request with key "A" today, and send "A" again two days later, the system will treat it as a completely new request.

Scenario Examples

  1. The client checks out order ORD-001, priced at Rp 100,000.
  2. The client sends to Gerbang Pay: X-Idempotency-Key: ORD-001, amount: 10000000.
  3. The Gerbang Pay server successfully creates the bill, but the connection drops while sending the response.
  4. The client application (thinking it failed) clicks "Pay" again.
  5. The client sends an automatic retry: X-Idempotency-Key: ORD-001, amount: 10000000.
  6. Gerbang Pay realizes the ID already exists. Instead of creating a new charge to the provider (Winpay/Midtrans) again, the system immediately returns the first payment object already in the database. THERE IS NO duplicate bill.

Failure Scenario (Conflict)

The client sends X-Idempotency-Key: ORD-001 with amount: 10000000.

Then the client changes their mind (or the shopping cart changes to Rp 150,000), but the client accidentally sends X-Idempotency-Key: ORD-001 again (the key is not regenerated).

The Gerbang Pay system detects the difference in amount, then returns:

json
{
  "success": false,
  "error": {
    "code": "IDEMPOTENCY_CONFLICT",
    "message": "idempotency conflict: Same key submitted with different payload"
  }
}

Solution for Clients: If the business parameters of an order change, the client must send the request with a completely new Idempotency Key, for example: ORD-001-v2.

Gerbang Pay API Documentation