Overview
All POST requests in the HopNow API require an Idempotency-Key header to prevent duplicate operations. This ensures safe retries when network errors or timeouts occur.
Do not include an Idempotency-Key with GET, PUT, PATCH, or DELETE requests. These methods are naturally idempotent.
How It Works
- Include a unique
Idempotency-Key (UUID format) in every POST request
- If a request is retried with the same key, HopNow returns the original response without performing the operation again
- This prevents duplicate payments, account creations, or other operations
Request Example
curl -X POST https://apis.hopnow.io/v1/transfers/payouts \
-H "Content-Type: application/json" \
-H "X-API-Key: your_api_key" \
-H "X-Signature: hmac_signature" \
-H "X-Timestamp: 1234567890" \
-H "X-Nonce: abc123..." \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-d '{
"account_id": "acct_123",
"beneficiary_id": "bene_456",
"amount": "1000.00",
"currency": "USD"
}'
Generating Keys
Use UUIDs for each new operation:
import uuid
idempotency_key = str(uuid.uuid4())
Best Practices
Store Keys in Your Database
Track idempotency keys with request state for reliable retry logic:
# Store key before making request
transaction = {
"idempotency_key": str(uuid.uuid4()),
"status": "pending",
"request_data": payout_data
}
db.save(transaction)
# Make request with stored key
response = client.post(
"/v1/transfers/payouts",
json=payout_data,
headers={"Idempotency-Key": transaction["idempotency_key"]}
)
Retry with Same Key
Always reuse the same idempotency key when retrying failed requests:
def create_payout_with_retry(payout_data, max_retries=3):
idempotency_key = str(uuid.uuid4())
for attempt in range(max_retries):
try:
response = client.post(
"/v1/transfers/payouts",
json=payout_data,
headers={"Idempotency-Key": idempotency_key}
)
return response.json()
except TimeoutError:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt) # Exponential backoff
Common Errors
{
"error": {
"type": "validation_error",
"code": "invalid_idempotency_key",
"message": "The idempotency key must be a valid UUID."
}
}
Solution: Use a properly formatted UUID (e.g., 550e8400-e29b-41d4-a716-446655440000)
Conflicting Request Body
{
"error": {
"type": "idempotency_error",
"code": "idempotency_key_conflict",
"message": "The request body does not match the original request for this idempotency key."
}
}
Solution: Use the same request body as the original request, or generate a new idempotency key for a different operation.