// Writing · Payments

Can an Indonesian company build its own payment gateway?

Mostly yes, and the part that stops you is not the one everybody warns you about. The licence probably does not apply to you. The QR code does.

·7 min readBank IndonesiaPJPQRISReconciliation

This question comes up in a specific shape. A company is paying an aggregator a fee on every transaction, someone does the arithmetic on a year of that, and the conclusion is we should just build our own payment gateway. Then the first person they ask says you need a Bank Indonesia licence, the second says you need a relationship at Bank Indonesia, and the project stops there.

Both of those answers are wrong, in different ways. Here is what actually decides it.

01

The question is not whether it is legal. It is whose money moves.

Indonesian payment providers are licensed by Bank Indonesia as a Penyedia Jasa Pembayaran, a PJP. The definition is the important part. Under PBI 23/6/PBI/2021, a PJP is a bank or non-bank institution that provides services facilitating payment transactions for service users. That is, for other people.

So the question to ask before anything else is not “are we building a payment gateway”. It is: does any money that is not ours ever sit in our account?

If your company is collecting payment for its own sales, it is the merchant. It is not providing a payment service to anyone. Whatever you build for that is an internal system, and calling it a “payment gateway” is a naming problem rather than a licensing one.

The moment that changes is specific and worth writing on a wall. If you start settling money to a third party, a seller on your platform, a partner outlet, another company in the group, then other people’s funds are passing through you, and you are in licensed territory. Marketplaces cross this line on day one and often do not notice, because from the code’s point of view it looks like the same checkout.

02

What a licence would actually cost, if you did need one

This matters because it reframes the advice you are being given. Since PBI 22/23/PBI/2020, “payment gateway” is no longer a licence you can apply for. The old scheme had separate permits for e-money, payment gateway, fund transfer and so on. They were folded into activity-based categories, and gateway-type work now sits inside payment initiation and acquiring services, which means categories 1 and 2.

Paid-up capital, per article 24(2) of PBI 23/6/PBI/2021:

Category 1Rp 15 billion

Source-of-funds information, payment initiation and acquiring, holding funds, remittance

Category 2Rp 5 billion

Source-of-funds information, payment initiation and acquiring

Category 3Rp 500 million / Rp 1 billion

Remittance and other activities set by Bank Indonesia

A non-bank applicant also needs at least 15 percent Indonesian ownership, and there is an ongoing capital requirement on top of the initial figure.

Read those numbers next to the original problem. If someone tells a company that wants to stop paying transaction fees on its own sales that the answer is a PJP licence, they are proposing a five to fifteen billion rupiah answer to a reconciliation problem. That is not caution. That is not having asked what the money is doing.

03

The route is published. It is not a relationship.

The other thing people say is that you need to know someone at Bank Indonesia. You do not, and this is checkable in about a minute.

Before you can apply as a PJP you are required to attend a Pre Consultative Meeting, and you request it through Bank Indonesia’s own e-licensing portal at bi.go.id/elicensing. The stated purpose of that meeting is to work out whether your business model even matches the licence you think you need, and to go through the documents before you submit anything.

Which means the consultation exists precisely to answer the question in section 01, for free, from the regulator, before anyone writes a line of code. If your prospective vendor did not mention it, that tells you something about how much of this they have actually done.

04

Where “build your own” genuinely stops: the QR code

Here is the part that surprises people, and it is the real constraint rather than the imagined one. Even when you are outside the licence entirely, even when it is unambiguously your own money, you cannot issue your own QRIS.

QRIS transactions are processed by licensed front-end providers acting as issuer or acquirer, and a merchant registers through one of them. The provider is what obtains your NMID, the national merchant ID, and produces the QR code. There is no path where a merchant generates a valid QRIS code by itself, and since 1 January 2020 QR-based payment acceptance in Indonesia has had to use the QRIS standard rather than a proprietary code.

So the honest split, for a company processing only its own transactions, is this:

  • Bank transfer and virtual accounts: genuinely yours to build. Direct host-to-host integration with individual banks is an established route, and it is where the per-transaction saving actually comes from.
  • QRIS: always through a licensed provider. Not a fee you can engineer away. You can negotiate it. You cannot remove it.
  • Cards: through an acquirer, same story.

That changes what the project is. It is not “replace the aggregator”. It is go direct where you are allowed to, stay on a licensed rail where you are not, and own the layer that sits above both. Which is a smaller, more achievable, and much more honest brief than the one people usually start with.

05

So what are you actually building?

Strip out the licensing argument and the work that remains is the same six things every time. None of them is the checkout page, and all of them are where real money goes wrong.

01

Idempotency

One payment produces one ledger entry, even when the bank delivers the same callback three times. This is not a nice-to-have. Retries are normal operation, not an error case, and a system that has not planned for them will double-count real money.

02

Signature verification

Payment state does not arrive from your frontend. It arrives from the bank as a server-to-server callback, and without signature verification anyone who learns the URL can tell your system a payment succeeded. This is the single cheapest thing to get right and the most common thing to get wrong.

03

A ledger that is not the bank statement

You need your own record of what you believe happened, kept separately from what the bank says happened, precisely so the two can be compared. If your internal record is derived from the statement, you have nothing to reconcile against and no way to detect a missing callback.

04

Reconciliation with an exceptions queue

Matching settlement files to internal orders is the easy half. The half that decides whether the system is usable is what happens to the rows that do not match: they need somewhere to go, an owner, and a workflow, rather than an alert nobody reads.

05

A status machine you can replay

Pending, paid, expired, refunded, with explicit transitions. Then a replay path for the case that will definitely happen: the callback that was never delivered at all. Without replay, your recovery procedure is someone editing the database by hand.

06

Routing and failover across banks

This is the honest answer to the biggest weakness of connecting to one bank directly. If that bank is down, you are down, and the aggregator you removed was quietly providing the alternative. Failover is the work you inherit when you cut out the middle.

Notice that an aggregator was doing four of these for you. That is what the fee was buying. The saving is real, but it is a transfer of work, not a removal of it.

06

When not to do this at all

I would rather lose the project than have someone build this and regret it, so here is the case against.

At low volume the aggregator fee is simply cheaper than the alternative, and the comparison people run is usually wrong because it counts only the fee. The real comparison is the fee against one integration per bank, plus the reconciliation you just inherited, plus being the person who gets called when a settlement file does not match. That last cost never appears in the spreadsheet that started the conversation.

There is a reasonable test, and it is not a number I can give you. It is three questions:

  • Does the annual fee you would save exceed the build, plus a year of maintaining it, by enough that you would still do it if the saving were half what you estimated?
  • Is there someone whose job it will be to work the exceptions queue every morning? If the answer is “we will figure that out”, you are not ready.
  • Can you tolerate one bank being down, or do you need the failover on day one? Because failover roughly doubles the smallest useful version of this.

If the honest answers are no, keep the aggregator and spend the money somewhere it compounds. That is not a defeat. Paying someone to absorb operational risk is a legitimate thing to buy.

07

Where I am speaking from

I have built the orchestration side and shipped it: a working escrow and split-payment demo with signature-verified webhooks, idempotent handlers, held funds, full and partial refunds, and a scheduled release job. It runs on Stripe in test mode, on Next.js and Supabase with row level security. It is a demo I built and own, not a client project, and it does not move real money. I say that plainly because a portfolio piece that quietly implies production scale gets found out in the second meeting.

On the Indonesian regulatory side I have done what is written here: read the regulations and Bank Indonesia’s own licensing pages, and stated where the boundary is and where it stops being a developer’s question. I have not taken a company through a PJP application, and I would tell you that before quoting rather than after.

If Stripe Connect is what you were actually reaching for, the country problem is a separate article: marketplace split payments when Connect does not support your country.

// Working through this?

If the aggregator is the right answer, I will say so.

The first question I will ask is whose money sits in the account, because everything else depends on it.