Konek QR

n8n and Make recipes: automate what happens when an invoice is paid

Connect Konek QR to n8n or Make without writing a server.

For example: every time an invoice is paid, add a row to Google Sheets, message your team, or update the order status in your shop. No server of your own to write.

These recipes use a webhook + check back with the API pattern: the Konek QR webhook is only the trigger, then the scenario fetches the invoice straight from the Konek QR API with your API key and only carries on if its status really is paid. A fake webhook cannot fake the API's answer, so you do not need to compute an HMAC signature in a no-code tool. (If you still want to verify the signature, see Verifying webhooks.)

What to set up in the Konek QR dashboard:

  • API → an API key with only the payments:read permission (enough for this recipe). Start with a kq_test_… test key.
  • Webhooks → a new endpoint with the URL from n8n or Make (steps below), the same mode as the key, and the payment.paid event.

n8n

  1. Create a new workflow and add a Webhook node:

    • HTTP Method: POST
    • Path: for example konekqr
    • Respond: Immediately (Konek QR needs a 2xx answer within 15 seconds)

    Copy its Production URL (it starts with https://) into the webhook endpoint in the Konek QR dashboard, then activate the workflow. The Test URL only works while you press "Listen for test event".

  2. Add an IF node: {{ $json.body.type }} is equal to payment.paid. This filters out "Send test event" (webhook.test), which carries no invoice.

  3. On the true branch, add an HTTP Request node:

    • Method: GET
    • URL: https://api.konekqr.web.id/v1/payments/{{ $json.body.data.id }}
    • Authentication: Generic Credential Type → Header Auth, with Name Authorization and Value Bearer kq_test_…
  4. Add a second IF node: {{ $json.payment.status }} is equal to paid. On its true branch, connect your action. Useful data:

    • {{ $json.payment.referenceId }}: your order id
    • {{ $json.payment.amount }}: the total paid (including the unique code)
    • {{ $json.payment.baseAmount }}: the price before the unique code
    • {{ $json.payment.paidAt }}, {{ $json.payment.paidVia }}, {{ $json.payment.paidLate }}
    • {{ $json.payment.metadata }}: the object you sent when you created the invoice
  5. Test it: in the Konek QR dashboard create a test invoice, then press Simulate payment. The run shows up in n8n's Executions tab.

A webhook can be delivered more than once (after a network drop, for example). Make your action safe to repeat: in Google Sheets, for example, use Append or Update Row with referenceId as the key column, not Append.

No public URL: pull events every minute

For n8n on a local network, replace the Webhook with a Schedule Trigger (every 1 minute) and read GET /v1/events:

  1. A Code node (JavaScript) to prepare the cursor:

    JavaScript
    const state = $getWorkflowStaticData('global');
    state.since ??= new Date().toISOString(); // events from before the workflow was active are not processed
    return [{ json: { after: state.cursor ?? '' } }];
  2. An HTTP Request to GET https://api.konekqr.web.id/v1/events with the same Header Auth (it needs the events:read permission) and Query Parameters after = {{ $json.after }}, types = payment.paid. Under Options → Response, turn on Never Error, so a 422 answer reaches the next step.

  3. A Code node to save the cursor and split the events into items:

    JavaScript
    const state = $getWorkflowStaticData('global');
    const res = $input.first().json;
    if (res.errors?.some((e) => e.field === 'after')) {
      delete state.cursor; // cursor older than 30 days: start again from the oldest event still kept
      return [];
    }
    if (!res.events) throw new Error(res.detail ?? 'Konek QR: the events request failed');
    if (res.next) state.cursor = res.next;
    return res.events.filter((e) => e.createdAt >= state.since).map((e) => ({ json: e.data }));

Static data is only saved on runs of an active workflow, not when you run it by hand from the editor. next moves forward even when there is no new payment.paid, and events are kept for 30 days, so a workflow that was down just carries on from its last cursor. If it was down for more than 30 days, its cursor is refused (422, field after) and step 3 starts it again.

Make

  1. Create a new scenario. First module: Webhooks → Custom webhook → Add → give it a name → copy its URL (https://hook.….make.com/…) into the webhook endpoint in the Konek QR dashboard.
  2. Press Redetermine data structure, then in the Konek QR dashboard press Send test event on that endpoint so Make learns the shape of the data. After that, simulate one test invoice so the invoice data structure is learned too.
  3. Second module: HTTP → Make a request, with a filter before it: type Equal to payment.paid (this filters out test events, which carry no invoice). Fill in the module:
    • URL: https://api.konekqr.web.id/v1/payments/{{1.data.id}}
    • Method: GET
    • Headers: Authorization = Bearer kq_test_…
    • Parse response: Yes
  4. Add a filter after the HTTP module: payment.status Equal to paid. A fake webhook with a made-up id stops here (or has already failed in the HTTP module with a 404).
  5. Add your action (Google Sheets, WhatsApp Business Cloud, email, Notion, …) with data from the HTTP module: payment.referenceId, payment.amount, payment.paidAt, payment.metadata.
  6. Turn the scenario on (Scheduling: Immediately as data arrives).

A Make custom webhook answers 200 Accepted as soon as the data arrives, so the 15-second limit is safe even when the scenario runs long.

Go live

  1. Create a live API key and replace Bearer kq_test_… in the HTTP node or module.
  2. Create a live webhook endpoint with the same URL (the test endpoint can stay for trying things).
  3. Create one small live invoice and pay it for real to make sure everything is connected.

If the webhook fails

Open the endpoint's delivery log in Dashboard → Webhooks. Webhook Doctor explains the cause, for example not_found (the n8n workflow is not active yet or uses the Test URL), auth_required (the Webhook node uses authentication), or cloudflare_challenge (self-hosted n8n behind Cloudflare). Once it is fixed, press Resend.

Something unclear or wrong? Write to [email protected].