Create a payment
All requests share the same shape: POST /v1/payments, Authorization: Bearer <API_KEY>, and an Idempotency-Key.
curl -sS -X POST \
https://ecmxmvrimionqhpbjguc.supabase.co/functions/v1/api-v1-payments/v1/payments \
-H "Authorization: Bearer $QASHX_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"amount": 1500,
"currency": "EUR",
"capability": "card_payment",
"customer": { "email": "buyer@example.com" }
}'const res = await fetch(
"https://ecmxmvrimionqhpbjguc.supabase.co/functions/v1/api-v1-payments/v1/payments",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.QASHX_API_KEY}`,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: 1500,
currency: "EUR",
capability: "card_payment",
customer: { email: "buyer@example.com" },
}),
}
);
const payment = await res.json();import { QashX } from "./qashx-sdk";
const client = new QashX({ apiKey: process.env.QASHX_API_KEY!, env: "sandbox" });
const payment = await client.payments.create({
amount: 1500,
currency: "EUR",
capability: "card_payment",
customer: { email: "buyer@example.com" },
});from qashx import QashX
client = QashX(api_key=os.environ["QASHX_API_KEY"], env="sandbox")
payment = client.payments.create(
amount=1500,
currency="EUR",
capability="card_payment",
customer={"email": "buyer@example.com"},
)package main
import (
"bytes"
"encoding/json"
"net/http"
"os"
"github.com/google/uuid"
)
func main() {
body, _ := json.Marshal(map[string]any{
"amount": 1500,
"currency": "EUR",
"capability": "card_payment",
"customer": map[string]string{"email": "buyer@example.com"},
})
req, _ := http.NewRequest("POST",
"https://ecmxmvrimionqhpbjguc.supabase.co/functions/v1/api-v1-payments/v1/payments",
bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("QASHX_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}HttpClient http = HttpClient.newHttpClient();
String body = """
{"amount":1500,"currency":"EUR","capability":"card_payment",
"customer":{"email":"buyer@example.com"}}
""";
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://ecmxmvrimionqhpbjguc.supabase.co/functions/v1/api-v1-payments/v1/payments"))
.header("Authorization", "Bearer " + System.getenv("QASHX_API_KEY"))
.header("Idempotency-Key", UUID.randomUUID().toString())
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> res = http.send(req, HttpResponse.BodyHandlers.ofString());using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("QASHX_API_KEY"));
http.DefaultRequestHeaders.Add("Idempotency-Key", Guid.NewGuid().ToString());
var payload = new {
amount = 1500, currency = "EUR", capability = "card_payment",
customer = new { email = "buyer@example.com" }
};
var res = await http.PostAsJsonAsync(
"https://ecmxmvrimionqhpbjguc.supabase.co/functions/v1/api-v1-payments/v1/payments",
payload);require "net/http"
require "json"
require "securerandom"
uri = URI("https://ecmxmvrimionqhpbjguc.supabase.co/functions/v1/api-v1-payments/v1/payments")
req = Net::HTTP::Post.new(uri, {
"Authorization" => "Bearer #{ENV['QASHX_API_KEY']}",
"Idempotency-Key" => SecureRandom.uuid,
"Content-Type" => "application/json"
})
req.body = { amount: 1500, currency: "EUR", capability: "card_payment",
customer: { email: "buyer@example.com" } }.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }<?php
$ch = curl_init("https://ecmxmvrimionqhpbjguc.supabase.co/functions/v1/api-v1-payments/v1/payments");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("QASHX_API_KEY"),
"Idempotency-Key: " . bin2hex(random_bytes(16)),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"amount" => 1500,
"currency" => "EUR",
"capability" => "card_payment",
"customer" => ["email" => "buyer@example.com"],
]),
]);
$response = curl_exec($ch);val client = OkHttpClient()
val body = """{"amount":1500,"currency":"EUR","capability":"card_payment",
"customer":{"email":"buyer@example.com"}}"""
.toRequestBody("application/json".toMediaType())
val req = Request.Builder()
.url("https://ecmxmvrimionqhpbjguc.supabase.co/functions/v1/api-v1-payments/v1/payments")
.addHeader("Authorization", "Bearer ${System.getenv("QASHX_API_KEY")}")
.addHeader("Idempotency-Key", java.util.UUID.randomUUID().toString())
.post(body).build()
client.newCall(req).execute().use { println(it.body?.string()) }Verify a webhook signature
All webhooks are signed with HMAC-SHA256. Reject any request older than 5 minutes.
import crypto from "crypto";
export function verify(payload, header, secret) {
const [ts, sig] = header.split(",").map(p => p.split("=")[1]);
const expected = crypto.createHmac("sha256", secret)
.update(`${ts}.${payload}`).digest("hex");
const fresh = Math.abs(Date.now()/1000 - Number(ts)) < 300;
return fresh && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}import hmac, hashlib, time
def verify(payload: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
ts, sig = parts["t"], parts["v1"]
expected = hmac.new(secret.encode(), f"{ts}.{payload.decode()}".encode(),
hashlib.sha256).hexdigest()
fresh = abs(time.time() - int(ts)) < 300
return fresh and hmac.compare_digest(sig, expected)func Verify(payload []byte, header, secret string) bool {
parts := strings.Split(header, ",")
ts := strings.TrimPrefix(parts[0], "t=")
sig := strings.TrimPrefix(parts[1], "v1=")
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(ts + "." + string(payload)))
expected := hex.EncodeToString(mac.Sum(nil))
tsN, _ := strconv.ParseInt(ts, 10, 64)
fresh := time.Now().Unix()-tsN < 300
return fresh && hmac.Equal([]byte(sig), []byte(expected))
}require "openssl"
def verify(payload, header, secret)
parts = header.split(",").map { |p| p.split("=", 2) }.to_h
expected = OpenSSL::HMAC.hexdigest("sha256", secret, "#{parts["t"]}.#{payload}")
fresh = (Time.now.to_i - parts["t"].to_i).abs < 300
fresh && Rack::Utils.secure_compare(expected, parts["v1"])
endRefund and list
All resource endpoints share the same auth. See the API reference for full parameters.
POST /v1/payments/{id}/refund -> refund a payment (idempotent)
GET /v1/payments/{id} -> retrieve a payment
GET /v1/payments?limit=20&starting_after=pay_... -> list (cursor-paginated)
POST /v1/payments/{id}/cancel -> cancel a pending payment