> For the complete documentation index, see [llms.txt](https://docs.gameket.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.gameket.io/introduction/concepts/idempotency.md).

# Idempotency

Idempotency ensures that requests with the same key produce the same result, even if executed multiple times.

#### Why Idempotency Matters

When making write operations over a network, sometimes you don't receive the response:

* Network timeout before response arrives
* Server processes the request but returns a 500 error
* Client crashes after sending a request

Without idempotency, retrying the request would create duplicates.

#### Using Idempotency Keys

**Format:** Any unique string (UUID recommended)

```bash
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
```

**Generate a UUID in JavaScript:**

```javascript
const uuid = crypto.randomUUID();
// or: const uuid = Math.random().toString(36).substr(2, 9);
```

#### Idempotency Behavior

1. **First request:** Server processes and returns a response.
2. **Duplicate request (same key):** Server returns cached response.
3. **New request (different key):** Server processes as a new request.

**Example:**

```bash
# Request 1: Creates a product
curl -X POST https://api.gameket.io/merchant/products \
  -H "Idempotency-Key: create-voucher-123" \
  -d '{"name": "Gift Card", "price": 100}'

# Response: Product created with ID "prod_xyz"

# Request 2: Same key, network timeout
curl -X POST https://api.gameket.io/merchant/products \
  -H "Idempotency-Key: create-voucher-123" \
  -d '{"name": "Gift Card", "price": 100}'

# Response: Same product returned (not duplicated!)
```

#### Idempotency Key Storage

Store the key with your request to enable retries:

{% tabs %}
{% tab title="Javascript" %}
{% code expandable="true" %}

```javascript
const idempotencyKey = crypto.randomUUID();
const request = {
  id: 'req_123',
  idempotencyKey,
  endpoint: '/merchant/products',
  body: { name: 'Gift Card', price: 100 },
  createdAt: new Date()
};

// Save request to DB/cache
await saveRequest(request);

// Make API call with idempotency key
const response = await fetch('https://api.gameket.io/merchant/products', {
  method: 'POST',
  headers: {
    'Idempotency-Key': idempotencyKey,
    // ... other headers
  },
  body: JSON.stringify(request.body)
});
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code expandable="true" %}

```python
import uuid
import sqlite3

def store_request_with_idempotency(endpoint, body):
    """Store request with idempotency key for retry ability"""
    idempotency_key = str(uuid.uuid4())
    
    # Save to database
    conn = sqlite3.connect('requests.db')
    cursor = conn.cursor()
    cursor.execute('''
        INSERT INTO requests (idempotency_key, endpoint, body)
        VALUES (?, ?, ?)
    ''', (idempotency_key, endpoint, str(body)))
    conn.commit()
    
    # Make API call with idempotency key
    response = requests.post(
        f'https://api.gameket.io{endpoint}',
        json=body,
        headers={'Idempotency-Key': idempotency_key}
    )
    
    return response
```

{% endcode %}
{% endtab %}

{% tab title="Rust" %}
{% code expandable="true" %}

```rust
use uuid::Uuid;
use serde_json::json;

pub struct RequestTracker {
    client: reqwest::Client,
}

impl RequestTracker {
    pub async fn track_and_send(
        &self,
        method: &str,
        endpoint: &str,
        body: serde_json::Value,
    ) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
        let idempotency_key = Uuid::new_v4().to_string();
        
        // Log request for audit trail
        println!("Sending {} {} with key {}", method, endpoint, idempotency_key);
        
        let mut req = match method {
            "POST" => self.client.post(format!("https://api.gameket.io{}", endpoint)),
            "PATCH" => self.client.patch(format!("https://api.gameket.io{}", endpoint)),
            _ => return Err("Unsupported method".into()),
        };

        let response = req
            .header("Idempotency-Key", idempotency_key)
            .json(&body)
            .send()
            .await?;

        Ok(response.json().await?)
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}
