Enter at least two characters to search. Searching documentation… No matching sections. Try an endpoint, field or event name.
Idempotency
View as MarkdownNetworks fail. To create a charge or link exactly once, send an Idempotency-Key header with any unique string of up to 255 characters (a UUID works well) on POST, PUT, PATCH and DELETE requests. Repeating the same key on the same endpoint, with the same body and query string, within 24 hours replays the original response instead of running the request again, and the replay carries an Idempotent-Replayed: true header.
On this page
Copy failed. Select the code and copy it manually.
curl -X POST 'https://api.velirapay.com/v1/charges' \
--fail-with-body --silent --show-error --max-time 30 \
-H "Authorization: Bearer ${VELIRAPAY_API_KEY:?Set VELIRAPAY_API_KEY}" \
-H 'Accept: application/json' \
-H 'Idempotency-Key: order-1042-attempt-1' \
-H 'Content-Type: application/json' \
-d '{
"amount": "150.00",
"currency": "USD",
"asset": "BTC"
}'
<?php
use VeliraPay\VeliraPayClient;
require __DIR__.'/vendor/autoload.php';
$apiKey = getenv('VELIRAPAY_API_KEY') ?: throw new RuntimeException('Set VELIRAPAY_API_KEY.');
$velirapay = new VeliraPayClient($apiKey, baseUrl: 'https://api.velirapay.com');
$charge = $velirapay->charges->create([
'amount' => '150.00',
'currency' => 'USD',
'asset' => 'BTC',
], idempotencyKey: 'order-1042-attempt-1');
echo json_encode($charge, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR), PHP_EOL;
use VeliraPay\Laravel\Facades\VeliraPay;
$charge = VeliraPay::charges()->create([
'amount' => '150.00',
'currency' => 'USD',
'asset' => 'BTC',
], idempotencyKey: 'order-1042-attempt-1');
const secretKey = process.env.VELIRAPAY_API_KEY;
if (!secretKey) throw new Error('Set VELIRAPAY_API_KEY.');
const response = await fetch('https://api.velirapay.com/v1/charges', {
method: 'POST',
headers: {
Authorization: `Bearer ${secretKey}`,
Accept: 'application/json',
'Idempotency-Key': 'order-1042-attempt-1',
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: '150.00',
currency: 'USD',
asset: 'BTC',
}),
redirect: 'error',
signal: AbortSignal.timeout(30_000),
});
if (!response.ok) {
throw new Error(`VeliraPay ${response.status}: ${await response.text()}`);
}
const charge = response.status === 204 ? null : (await response.json()).data;
console.log(JSON.stringify(charge, null, 2));
import json
import os
import requests
api_key = os.environ["VELIRAPAY_API_KEY"]
response = requests.post(
"https://api.velirapay.com/v1/charges",
headers={
"Authorization": f"Bearer {api_key}",
"Accept": "application/json",
"Idempotency-Key": "order-1042-attempt-1",
},
json={
"amount": "150.00",
"currency": "USD",
"asset": "BTC",
},
timeout=(5, 30),
allow_redirects=False,
)
if not 200 <= response.status_code < 300:
raise RuntimeError(f"VeliraPay {response.status_code}: {response.text}")
charge = None if response.status_code == 204 else response.json()["data"]
print(json.dumps(charge, indent=2))
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var secretKey = Environment.GetEnvironmentVariable("VELIRAPAY_API_KEY")
?? throw new InvalidOperationException("Set VELIRAPAY_API_KEY.");
using var client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false })
{
Timeout = TimeSpan.FromSeconds(30),
};
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.velirapay.com/v1/charges");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secretKey);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Add("Idempotency-Key", "order-1042-attempt-1");
request.Content = new StringContent("""
{
"amount": "150.00",
"currency": "USD",
"asset": "BTC"
}
""", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException($"VeliraPay {(int)response.StatusCode}: {responseBody}");
}
JsonElement? charge = null;
if (response.StatusCode != HttpStatusCode.NoContent)
{
using var document = JsonDocument.Parse(responseBody);
charge = document.RootElement.GetProperty("data").Clone();
}
Console.WriteLine(charge?.GetRawText() ?? "null");
What a key covers
A key belongs to one account, one mode and one endpoint, meaning the method and the full path: the same key sent to POST /v1/charges/{id}/refunds of two different charges makes two separate requests. Every API key of the account shares the same keys within a mode, while the same key on a test request and on a live one are two separate requests, so the same order number can safely drive both.
A key is also tied to the body it was first sent with. Sending it again with a different body answers 409 rather than replaying a response that describes something you did not ask for. While the first request carrying a key is still being worked on, for up to 60 seconds, a second one answers 409 with Retry-After: 1: retrying a request whose answer never arrived is the case this header exists for, and waiting beats making the thing twice.
Only a successful response is stored, so a request that failed can simply be sent again under the same key. A replay repeats the stored status and JSON body, not the other headers of the original response. A response carrying a secret, a new API key or a webhook signing secret, is not stored: repeating it answers 409, saying the request already succeeded, since the secret is shown once. A key longer than 255 characters answers 400. GET requests ignore the header, and the MCP server does not use it.