# Idempotency Keys

### Overview

When making API requests that create resources (checkouts, installment requests), network issues or timeouts may cause you to miss the response even though JeelPay successfully processed the request. Without protection, retrying such a request would create a **duplicate** — resulting in the customer receiving multiple payment links.

**Idempotency keys** solve this problem. By including a unique key with your request, JeelPay guarantees that retrying the same request will return the original response without creating a duplicate.

***

### How It Works

1. Generate a unique string (we recommend a UUID) and send it as the `Idempotency-Key` header.
2. JeelPay processes the request and caches the response against your key.
3. If you retry with the **same key**, JeelPay returns the cached response — no new resource is created.
4. If you send a **different key**, JeelPay treats it as a new request.

Keys are scoped to your group (API credentials) and the specific endpoint, meaning `key-123` on `/v3/checkout/schooling` and `key-123` on `/v3/checkout` are treated independently.

> **Key Expiration:** Idempotency keys are automatically cleaned up after **24 hours**. After that, the same key can be reused.

***

### Recommended Integration Flow

To ensure data consistency, we recommend creating a record in your database **before** calling the JeelPay API. This ensures you always have the Idempotency Key saved to retry in case of a timeout.

```mermaid
sequenceDiagram
    autonumber
    participant App as Your System
    participant DB as Your Database
    participant API as JeelPay API

    Note over App, DB: 1. Preparation Phase
    App->>App: Generate UUID (Key: 123-abc)
    App->>DB: INSERT Record (Key: 123-abc, Status: PENDING)
    activate DB
    DB-->>App: Record Saved
    deactivate DB

    Note over App, API: 2. Execution (Network Timeout)
    App->>API: POST /checkout (Header: Idempotency-Key: 123-abc)
    activate API
    Note right of API: JeelPay processes request.<br/>Resource created.
    API--xApp: Network Error / Timeout (Response Lost)
    deactivate API

    Note left of App: No response received.<br/>Trigger Retry Logic.

    Note over App, API: 3. Retry (Using Stored Key)
    App->>DB: Fetch Pending Record (Key: 123-abc)
    activate DB
    DB-->>App: Returns Key: 123-abc
    deactivate DB
    App->>API: POST /checkout (Header: Idempotency-Key: 123-abc)
    activate API
    Note right of API: Key found in cache.<br/>Returns original response.
    API-->>App: 200 OK (Cached Response)
    deactivate API

    Note over App, API: 4. continue the flow normally
    

```

***

### Supported Endpoints

| Endpoint                   | Method | Description                   |
| -------------------------- | ------ | ----------------------------- |
| `/v3/checkout/schooling`   | POST   | Create a schooling checkout   |
| `/v3/checkout`             | POST   | Create an items checkout      |
| `/v2/installment-requests` | POST   | Create an installment request |

***

### Usage

Add the `Idempotency-Key` header to your request. The value must be a unique string (max 255 characters).

#### Example — Schooling Checkout

```bash
curl -X POST https://api.jeel.co/v3/checkout/schooling \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "buyer": { ... },
    "students": [ ... ],
    "urls": { ... },
    "metadata": { "orderId": "ORD-123" },
    "referenceId": "ref-001"
  }'

```

#### Example — Items Checkout

```bash
curl -X POST https://api.jeel.co/v3/checkout \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -d '{
    "buyer": { ... },
    "items": [ ... ],
    "urls": { ... },
    "metadata": { "orderId": "ORD-123" },
    "referenceId": "ref-001"
  }'

```

#### Example — Installment Request (V2)

```bash
curl -X POST https://api.jeel.co/v2/installment-requests \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-456" \
  -d '{ ... }'

```

***

### Retry Behavior

| Scenario                                                | Result                                                       |
| ------------------------------------------------------- | ------------------------------------------------------------ |
| First request with `Idempotency-Key: abc`               | Checkout/request is created, response is returned and cached |
| Retry with `Idempotency-Key: abc` (same key)            | **Cached response returned** — no duplicate created          |
| New request with `Idempotency-Key: xyz` (different key) | A new checkout/request is created                            |
| Request without `Idempotency-Key` header                | Request is processed normally (no caching)                   |

***

### Best Practices

1. **Always send an idempotency key** on checkout and installment request creation endpoints.
2. **Use UUIDs** — they are globally unique and easy to generate in any language.
3. **Generate a new key for every distinct request** — do not reuse keys across different intended requests.
4. **Store the key** alongside your order/transaction so you can correlate retries.
5. **Implement proper retry logic** — on timeout or `5xx` errors, retry with the same idempotency key.

#### Key Generation Examples

```javascript
// JavaScript / Node.js
const idempotencyKey = crypto.randomUUID();

```

```python
# Python
import uuid
idempotency_key = str(uuid.uuid4())

```

```java
// Java
String idempotencyKey = UUID.randomUUID().toString();

```

```php
// PHP
$idempotencyKey = wp_generate_uuid4(); // WordPress
// or
$idempotencyKey = \Ramsey\Uuid\Uuid::uuid4()->toString();

```

***

### FAQ

**Is the `Idempotency-Key` header required?** No, it is optional. However, we **strongly recommend** always including it to protect against duplicate resource creation during timeouts.

**What happens if I don't send the header?** The request is processed normally. If a timeout occurs and you retry, a duplicate checkout or installment request will be created.

**How long is a key valid?** Keys expire after **24 hours**. After expiration, the same key value can be reused for a new request.

**Can I use the same key across different endpoints?** Yes — keys are scoped per endpoint. The key `abc` on `/v3/checkout/schooling` is independent from `abc` on `/v3/checkout`.

**What if the original request failed with a validation error?** Only successful responses (HTTP 200) are cached. If the original request failed, retrying with the same key will process the request again.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.jeel.co/idempotency-keys.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
