API v1.0.0OpenAPI 3.0

Wayl API — payment lifecycle

Links, status, webhooks, refunds — full schemas and try-it requests are in the API reference.

Step 1

Overview

With Wayl's API you create payment links so customers can check out, you can subscribe to webhooks when order status changes, and you can run refunds when you need to reverse a charge. Send every request to: https://api.thewayl.com.

The sections below are a short walkthrough of that flow. For every field, validation rule, and try-it request, use the hosted API reference.

Responses are JSON. On success you'll usually get a data object (the resource) and a message string — often with HTTP 200 or 201. If something goes wrong, 4xx responses usually include a message (and sometimes an errors list with more detail).

API token

  1. After creating an account, send an email to jisr@wayl.io to request an API token.
  2. Keep it server-side only (treat it like a password).
  3. Send it on every request: X-WAYL-AUTHENTICATION.

Header

Name
X-WAYL-AUTHENTICATION
Value
Your merchant token

Flow

In practice: you create a link, the customer pays, you may receive a webhook when status updates, and you can refund if the situation calls for it. The same referenceId ties the whole order together end to end.

Sequence diagram: the merchant backend requests a payment link from the Wayl API, receives a URL, redirects the customer to that URL, the customer pays on Wayl hosted checkout, then Wayl notifies the merchant backend with a webhook.Merchant backendYour serversWayl APIapi.thewayl.comCustomerBrowser / appWayl checkoutHosted paymentCreate link · X-WAYL-AUTHENTICATIONResponse · checkout URLRedirect customer to URLCustomer paysWebhook · notify merchantTime →
Your merchant backend calls the Wayl API to create a link, gets back a checkout URL, sends the customer there (redirect), the customer completes payment on Wayl-hosted checkout, then Wayl notifies your backend with a webhook. Use X-WAYL-AUTHENTICATION on API requests.

Step 3

Check payment status

Any time you need to know where an order stands—after a redirect, from a cron job, or before you ship—you can ask Wayl for the current link by the same referenceId you used when you created it. Call GET /api/v1/links/{referenceId} — the response tells you whether it's still open, paid, or finished, and when things changed. status moves through values like Created, Pending, Processing, Complete, Delivered, Cancelled, Rejected, and Returned; the hosted API reference has the full list and meanings.

Example (curl)

curl -s "https://api.thewayl.com/api/v1/links/order-1001" \
-H "X-WAYL-AUTHENTICATION: YOUR_MERCHANT_TOKEN"

A successful lookup returns 200 with that link in data. Use status for the lifecycle, paymentMethod once the customer has paid (if present), and completedAt when you need the time the payment completed.

Example response (200 · JSON)

{
"data": {
"referenceId": "order-1001",
"id": "cmlink_01hq_example",
"total": "10000",
"currency": "IQD",
"paymentMethod": "Card",
"status": "Complete",
"completedAt": "2025-04-09T12:07:30.000Z",
"createdAt": "2025-04-09T12:00:00.000Z",
"updatedAt": "2025-04-09T12:07:30.000Z",
"url": "https://checkout.thewayl.com/pay/I94F590I",
"webhookUrl": "https://example.com/webhooks/wayl",
"redirectionUrl": "https://example.com/thanks"
},
"message": "Link retrieved successfully."
}

Step 4

Webhooks & verify

If you'd rather not poll the API, you can give Wayl a webhookUrl when you create the link. When something important changes, Wayl sends your server a POST with JSON. You also set a webhookSecret so you can prove the request really came from Wayl: each delivery includes x-wayl-signature-256, a signature over the request body.

Before you act on the JSON, compute the signature yourself and compare it to that header—using the raw body bytes exactly as received (not a re-serialized copy), so you don't accidentally accept a forged request.

While you're building, point webhookUrl at a throwaway URL from webhook.site so you can inspect payloads and headers without touching production.

Webhook inspector: POST with x-wayl-signature-256 and JSON body.
Typical inspection view: x-wayl-signature-256 next to the raw JSON body.

Example body (JSON)

{
"verb": "POST",
"event": "order.created",
"referenceId": "dassasasuaassasmmy-rzel2faserasaseneas-id",
"paymentMethod": "...",
"paymentStatus": "...",
"paymentProcessor": "...",
"total": 1000,
"commission": 0,
"code": "I94F590I",
"customer": {
"id": "cmBkktqmz0000g00btwuo4ill",
"name": "...",
"phone": "...",
"city": "iraq_al_basrah",
"country": "IQ",
"address": "Baghdad"
},
"items": [
{
"type": "increase",
"label": "Basket Value",
"amount": 1000
}
],
"id": "cmay0lf12000ng0194x5r801o"
}

Respond

When you've accepted the payload and queued work, reply with any HTTP 2xx status code. If Wayl sees an error or a timeout, it may try again—so keep your endpoint quick (do heavy work in the background) and return success only once you've safely stored the event.

Verify HMAC

Use the same webhookSecret you used when creating the link. Hash the raw body with HMAC-SHA256 and compare the result to the x-wayl-signature-256 header using a constant-time comparison so timing attacks can't leak information.

Node.js

import crypto from "crypto";
function verifyWebhookSignature(data, signature, secret) {
// data from webhook req.body
// signature from req.headers "x-wayl-signature-256"
// secret that was previously sent when creating the link, should be locally
// stored in your code or database
// generate signature from data and secret
const calculatedSignature = crypto.createHmac("sha256", secret).update(data).digest("hex");
// Convert the signatures to buffers for security
const signatureBuffer = Buffer.from(signature, "hex");
const calculatedSignatureBuffer = Buffer.from(calculatedSignature, "hex");
// Compare the created signature with the signature from the request
if (signatureBuffer.length !== calculatedSignatureBuffer.length) {
return false;
}
return crypto.timingSafeEqual(signatureBuffer, calculatedSignatureBuffer);
// true if the signature is valid, false otherwise
}
verifyWebhookSignature(data, signature, secret);

Sign the exact bytes Wayl posted—typically the buffer or string you read from the request before you call JSON.parse, so whitespace and ordering stay identical.

Step 5

Refunds

When you need to return money to a customer after a successful charge, you open a refund against the same order using POST /api/v1/refunds. You send the order's referenceId, how much to refund in IQD as amount (up to what was captured), and a clear reason (100–1500 characters) so support and risk teams can see why. Wayl tracks each refund with a status such as Requested, Refunded, Rejected, or Cancelled.

Example (curl)

curl -s -X POST "https://api.thewayl.com/api/v1/refunds" \
-H "X-WAYL-AUTHENTICATION: YOUR_MERCHANT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"referenceId": "order-1001",
"reason": "Customer requested a refund after a duplicate charge. Support ticket #4521 confirms the issue; merchant policy allows a full reversal within fourteen days of purchase.",
"amount": 10000
}'

If the refund request is accepted, you'll get 201 and a data object with the refund's id, linkId, amount, who started it (initiatedBy), and the current status.

Example response (201 · JSON)

{
"data": {
"id": "cmrefund_01hq_example",
"reason": "Customer requested a refund after a duplicate charge. Support ticket #4521 confirms the issue; merchant policy allows a full reversal within fourteen days of purchase.",
"linkId": "cmlink_01hq_example",
"referenceId": "order-1001",
"amount": 10000,
"initiatedBy": "Merchant",
"status": "Requested"
},
"message": "Refund created successfully."
}

Listing refunds and cancelling a pending request are documented in the hosted API reference.

Full reference

Schemas, status codes, try-it — on the hosted API docs.

Open full API reference