Skip to main content

How do I create my first payment through the API?

Six steps: get your keys, choose an access mode, set your webhook URL, enable methods, create a payment in sandbox, then verify the webhook and go live. Sandbox and production share the same keys and URLs, so going live changes nothing but the account mode.

This page was checked against the API code as of October 16, 2026.

What do I need before writing code?#

  • A merchant account that has passed verification (KYC). Until then, POST /payment returns 403 MERCHANT_KYC_INCOMPLETE.
  • A server reachable from the internet to receive webhooks. Internal addresses such as localhost or private IPs are rejected as callback_url.
  • Access to the merchant dashboard to copy your keys and set URLs.

In what order should I integrate?#

  1. Get your API key and secret key

    Dashboard, API Settings, then API Keys. The secret key is shown after PIN verification. Keep it in a server environment variable, never in client code or a repository.

  2. Choose an access mode

    API Settings, Mode & access. Fixed-IP server: register its IP (IP Whitelist). Serverless: turn the whitelist off to use Enhanced HMAC. The differences are in Authentication.

  3. Set the webhook and return URLs

    API Settings, Webhook & Return URL. Both can be overridden per payment with the callback_url and return_url fields.

  4. Enable payment methods

    Payment methods in the dashboard. Only methods enabled on your account can be used, and GET /payment-methods returns exactly that list with each payment_code.

  5. Turn on sandbox and create a payment

    Sandbox mode is under Mode & access. Send the request below, open the payment_link from the response, then click simulate success.

  6. Verify the webhook, then turn sandbox off

    Make sure your endpoint verifies X-Signature and answers 2xx. Then turn sandbox off; keys and URLs stay the same.

What does the first request look like?#

This example is for IP Whitelist mode: only POST requests are signed, with HMAC-SHA256 over the JSON body exactly as sent. For Enhanced HMAC, see its example.

BODY='{"merchant_ref_id":"ORDER-2026-00184","amount":150000,"payment_code":"QRIS","customer_name":"Budi Santoso","customer_email":"[email protected]","customer_phone":"081234567890","callback_url":"https://toko-anda.id/webhook/sekalipay","return_url":"https://toko-anda.id/checkout/selesai"}'
SIGNATURE=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SEKALIPAY_SECRET_KEY" | sed 's/^.* //')

curl -X POST https://sekalipay.com/api/v1/gateway/payment \
  -H "X-API-Key: $SEKALIPAY_API_KEY" \
  -H "X-Signature: $SIGNATURE" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  --data-raw "$BODY"
201 Created
{
  "status": true,
  "message": "OK",
  "data": {
    "merchant_ref_id": "ORDER-2026-00184",
    "invoice": "SPY1791446400K3QZ",
    "amount": 150000,
    "fee": 1500,
    "total": 151500,
    "payment_code": "QRIS",
    "payment_link": "https://sekalipay.com/payment/SPY1791446400K3QZ",
    "qr_link": "https://sekalipay.com/payment/SPY1791446400K3QZ/qris",
    "virtual_account": null,
    "checkout_url": null,
    "payment_guide": null,
    "expired_at": "2026-10-08T08:30:00.000000Z",
    "status": "pending",
    "is_sandbox": false
  }
}

What must I check before going live?#

  • Webhooks are verified with an HMAC over the raw body and compared in constant time (how).
  • Orders are marked paid only from the webhook or a status check, never from parameters on return_url.
  • Webhook processing is idempotent, because the same webhook can arrive more than once.
  • The webhook amount is matched against the order before goods are delivered.
  • Every order has a unique merchant_ref_id, and retries after a timeout reuse the same ref (idempotency).
  • Both paid and completed are treated as paid (why).
  • 429 responses are handled by waiting for the Retry-After header.
  • Sandbox mode is turned off.

Ready to use your own keys?

Sign in to the merchant dashboard to copy your API key and secret key, set the access mode and webhook URL, and download a Postman collection with your account's keys.

Sign in to the dashboard