Accept payments
Hosted checkout
Create checkout on your server, then open it from your website.
Create a checkout session
Use POST /checkout/sessions with a server key that has payments:write. The session fixes the amount on the server. Save the returned data.id against the order.
curl https://api.veyqo.org/api/v1/checkout/sessions \
-H "Authorization: Bearer $VEYQO_SECRET_KEY" \
-H "Idempotency-Key: $ORDER_PAYMENT_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 50000,
"currency": "NGN",
"reference": "ORDER-1001",
"provider": "paystack",
"customer": { "email": "customer@example.com" },
"success_url": "https://shop.example.com/thanks",
"cancel_url": "https://shop.example.com/cart"
}'Open checkout in the browser
Expose your own authenticated /create-checkout endpoint that looks up the order, creates the session and returns { id: result.data.id }. Check that the signed-in customer owns the order.
<script src="https://veyqo.org/sdk/v1/checkout.js"></script>
<button id="pay">Pay now</button>
<script>
document.getElementById("pay").onclick = async () => {
try {
const response = await fetch("/create-checkout", { method: "POST" });
if (!response.ok) throw new Error("Could not create checkout");
const { id } = await response.json();
VeyqoCheckout.open({
session: id,
onSuccess: () => location.assign("/thanks"),
onClose: () => console.log("Checkout closed"),
});
} catch (error) {
alert("Unable to open checkout. Please try again.");
}
};
</script>Choose the correct trust boundary
Recommended: create the session on your server with a kc_test_ or kc_live_ secret key, save the returned cs_ ID against your order, then open data.url or call VeyqoCheckout.open({ session: id }). The server fixes the amount and currency.
The publishable-key browser flow lets the page set amount, reference and customer data. Treat those as untrusted input. Compare the actual paid amount/currency and ownership against your server-side order before fulfilling. A publishable key is not a secret API key.
Browser checkout script
Load the Veyqo-hosted script directly. There is no claimed npm SDK or MCP server for this integration. The open call returns a Promise; catch request or setup errors. A blocked popup falls back to a redirect. Call it from a user click.
<script src="https://veyqo.org/checkout.js"></script>
<script>
// sessionId comes from your server's POST /checkout/sessions response.
document.querySelector('#pay').addEventListener('click', () => {
VeyqoCheckout.open({
session: sessionId,
onSuccess(result) {
// result: { session, reference, status: 'success' }
// Ask your server for the order state; do not fulfil in this callback.
refreshOrderStatus();
},
onClose(result) {
// Closing a popup is not proof the payment failed.
refreshOrderStatus();
},
}).catch(showCheckoutError);
});
</script>Checkout script options and callbacks
setup({ key, apiUrl, checkoutOrigin }) configures browser-created sessions. key is a pk_test_ or pk_live_ publishable key; apiUrl comes from the script’s deployment configuration; the production script targets https://api.veyqo.org. checkoutOrigin is the origin serving the script (https://veyqo.org in production). A server-created session does not require setup({ key }).
open({ session, mode, onSuccess, onClose, onError }) opens a saved cs_ ID. mode defaults to popup; redirect navigates the current window. Its Promise resolves with { session } after checkout opens, not after payment completion.
For browser-created sessions, omit session and supply amount, currency, email, name, reference, description, metadata, provider, successUrl and cancelUrl as needed. amount and currency are required. These camelCase SDK options map to the documented snake_case browser request.
onSuccess receives { session, reference, status: success }. onClose receives { session, status }, including closed. onError receives an Error; open also rejects, so attach a catch handler. Callbacks work while the popup opener remains available; redirect mode requires your return page and server-side reconciliation.
Advanced browser API
The hosted page and checkout script use /checkout/v1, not /api/v1. Its session detail replaces the provider slug with a provider object and includes methods and next_action. These provider-dependent instructions are intentionally handled by the hosted client.
Creating a browser session accepts Authorization: Bearer <publishable-key> or X-Veyqo-Key. Success/cancel URL hosts must match the request Origin. Subsequent session calls use the session ID, without a secret key.
Session lifecycle and payment attempts
Sessions are open, completed or expired. Default lifetime: 60 minutes. A completed or expired session cannot be reused as a new order.
One session may have several payment attempts as a customer tries another method. The first attempt uses the base reference; later attempts can have a numeric suffix. Store the session ID and reconcile its current payment ID against your server order, rather than assuming every attempt reference equals the original order reference.
Payment metadata includes checkout_session, checkout_source and, when supplied, merchant_reference. Metadata alone is not proof of ownership: fetch the session/payment with the original project key and compare the stored session/payment relationship, amount and currency. Investigate ambiguous late outcomes before fulfilling.