One API for every bank. Built and run for you.

In addition to our unified API, Acme handles the project management, implementation and maintenance with the bank on your behalf — cutting the time to go live by up to 80% (go live in 6–8 weeks, not 6–10 months).

50+integrations built
40+live with DBS
~80%faster to go-live
You keepcustody of every dollar

The first integrator featured on Standard Chartered's own Open Banking portal (Chocolate Finance, Singapore + Hong Kong).

Acme simplifies bank integrations in APAC.

Connecting to your bank is complex and time-consuming. Projects can drag on 6–10 months even with a dedicated engineering and project team. Acme simplifies that.

Done-for-you
1

Direct REST API

Use Acme's unified APIs to connect directly to your bank accounts with full control and flexibility.

2

Ownership retained

You retain full ownership of your bank credentials and accounts; Acme never touches or holds your money.

3

Complexity simplified

We study and digest every bank's API/SFTP docs, build and maintain the connections, and expose a single, streamlined API to you.

Two ways to integrate

A

Direct REST API

Connect directly to your bank accounts with full control and flexibility.

Read the API docs
B

ERP Connection (No Code)

Connect via NetSuite or Business Central app. Acme is the only proper bank-connectivity layer for NetSuite in Singapore.
Integrate via our SI partner Lancia Consult.

Top use cases

1

Instant transaction notifications & bank feeds

Webhooks for every transaction that hits your bank account in real time, deduplicated against the hourly and daily statement.

2

Payouts

Trigger payment instructions to vendors, customers or internal accounts; choose approval workflow in the bank portal or straight-through processing.

3

FX

Real-time FX quotes and execution via API.

4

Hosted payment solutions

Collect payments from your customers straight into your bank account. We integrate each bank’s collection solution and handle the complexity, so your team writes minimal code.

5

Multi-bank expansion

Add new banks or regions at any time; Acme handles onboarding in the same API and connector.

6

Static virtual accounts

Named VAs to collect or pay on behalf of your end-clients (COBO and POBO).

Why Acme stands out

1

End-to-end project delivery

We scope, test and deploy every bank connection with you, including all the bank project management and paperwork.

2

Single API surface

One REST API abstracts all bank protocols (API, SFTP, file formats), so you integrate once.

3

Speed to market

Go live in 6–8 weeks, not a year.

4

Reduced headcount

No large in-house team to build or maintain bank connections.

APAC-led. Global by design.

Singapore & SEA

Deepest direct bank and payment rails coverage across South East Asia with 40+ live DBS integrations: eGIRO, PayNow, full payments stacks.

Asia-Pacific

Hong Kong + wider region via direct pipes and global partners.

Global

Featured on Standard Chartered's Open Banking portal, plus global networks. If your bank isn't listed, we build it.

DBS logo
Standard Chartered logo
Standard Chartered logo
Standard Chartered logo

Don't see your bank? Adding a bank is what we do.

Request POST /v1/payments
curl -X POST https://api.tryacme.com/v1/payments \
  -H "Authorization: Bearer $ACME_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 00000000-0000-4000-8000-000000000001" \
  -d '{
    "type": "FAST",
    "amount": 150000,
    "currency": "SGD",
    "senderAccountId": "intacc_0EXAMPLE00001",
    "customerReference": "INV-0001",
    "receiver": {
      "name": "Example Supplier Pte Ltd",
      "bank": "OCBCSGSGXXX",
      "bankAccountNumber": "0000000001"
    }
  }'
Request POST /v1/payments
import crypto from "node:crypto";

const res = await fetch("https://api.tryacme.com/v1/payments", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.ACME_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    type: "FAST",
    amount: 150000, // SGD 1,500.00 in minor units
    currency: "SGD",
    senderAccountId: "intacc_0EXAMPLE00001",
    customerReference: "INV-0001",
    receiver: {
      name: "Example Supplier Pte Ltd",
      bank: "OCBCSGSGXXX",
      bankAccountNumber: "0000000001",
    },
  }),
});

const payment = await res.json();
console.log(payment.id, payment.status);
Request POST /v1/payments
import os, uuid, requests

resp = requests.post(
    "https://api.tryacme.com/v1/payments",
    headers={
        "Authorization": f"Bearer {os.environ['ACME_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "type": "FAST",
        "amount": 150000,  # SGD 1,500.00 in minor units
        "currency": "SGD",
        "senderAccountId": "intacc_0EXAMPLE00001",
        "customerReference": "INV-0001",
        "receiver": {
            "name": "Example Supplier Pte Ltd",
            "bank": "OCBCSGSGXXX",
            "bankAccountNumber": "0000000001",
        },
    },
)

payment = resp.json()
print(payment["id"], payment["status"])
Send a test event transactions.created
# Acme POSTs each event to your HTTPS webhook endpoint.
# Replay a saved event against your own handler:
curl -X POST https://your-app.example.com/webhooks/acme \
  -H "Acme-Timestamp: 2026-10-08T03:14:07Z" \
  -H "Acme-Signature: <hex HMAC-SHA256 of timestamp|body>" \
  --data-binary @event.json
Verify & handle transactions.created
import crypto from "node:crypto";
import express from "express";

const app = express();

app.post("/webhooks/acme", express.text({ type: "*/*" }), (req, res) => {
  // Signature = hex HMAC-SHA256 of "<Acme-Timestamp>|<raw body>"
  const expected = crypto
    .createHmac("sha256", process.env.ACME_WEBHOOK_SIGNING_KEY)
    .update(`${req.get("Acme-Timestamp")}|${req.body}`)
    .digest("hex");
  const signatures = (req.get("Acme-Signature") || "").split(",");
  if (!signatures.includes(expected)) return res.sendStatus(400);

  const event = JSON.parse(req.body);
  if (event.event === "transactions.created") {
    for (const txn of event.objects ?? [event.object]) {
      if (txn.direction === "CREDIT") {
        // match txn.customerReference / txn.amount to an open invoice
      }
    }
  }
  res.sendStatus(200); // reply 200 within 5 seconds
});
Verify & handle transactions.created
import hashlib, hmac, os
from flask import Flask, request

app = Flask(__name__)

@app.post("/webhooks/acme")
def acme_webhook():
    # Signature = hex HMAC-SHA256 of "<Acme-Timestamp>|<raw body>"
    message = request.headers["Acme-Timestamp"] + "|" + request.get_data(as_text=True)
    expected = hmac.new(
        os.environ["ACME_WEBHOOK_SIGNING_KEY"].encode(),
        message.encode(),
        hashlib.sha256,
    ).hexdigest()
    if expected not in request.headers.get("Acme-Signature", "").split(","):
        return "", 400

    event = request.get_json()
    if event["event"] == "transactions.created":
        for txn in event.get("objects") or [event["object"]]:
            if txn["direction"] == "CREDIT":
                pass  # match txn["customerReference"] / txn["amount"] to an open invoice
    return "", 200  # reply 200 within 5 seconds
Response 200 · abridged
{
  "id": "pymt_0EXAMPLE00001",
  "type": "FAST",
  "amount": 150000,
  "currency": "SGD",
  "customerReference": "INV-0001",
  "senderAccountId": "intacc_0EXAMPLE00001",
  "receiver": {
    "name": "Example Supplier Pte Ltd",
    "bank": "OCBCSGSGXXX",
    "bankAccountNumber": "0000000001"
  },
  "status": "PROCESSING",
  "resultCode": null,
  "bankReference": null,
  "createdAt": "2026-10-08T02:15:32.418Z",
  "updatedAt": "2026-10-08T02:15:32.418Z"
}
Webhook body abridged
{
  "id": "wbh_0EXAMPLE00001",
  "createdAt": "2026-10-08T03:14:07.429871266Z",
  "mode": "TEST",
  "event": "transactions.created",
  "object": {
    "id": "txn_0EXAMPLE00001",
    "dataSource": "ICN",
    "transactionType": "PAYNOW",
    "transactionStatus": "BOOKED",
    "bankReference": "EXAMPLEBANKREF0001",
    "customerReference": "INV-0001",
    "amount": 128050,
    "currency": "SGD",
    "direction": "CREDIT",
    "counterparty": {
      "name": "EXAMPLE CUSTOMER PTE LTD",
      "bank": "OCBCSGSGXXX",
      "bankAccountNumber": "0000000002"
    },
    "bankAccount": {
      "id": "intacc_0EXAMPLE00001",
      "bank": "DBSSSGSGXXX",
      "bankAccountNumber": "0000000001"
    },
    "virtualAccountNumber": null,
    "transactionDate": "2026-10-08",
    "statementId": null,
    "createdAt": "2026-10-08T03:14:07.418Z",
    "updatedAt": "2026-10-08T03:14:07.418Z"
  }
}

Sample values only. Every field, status and event is in the Acme API reference.

Full reference, sandbox keys and SDKs in the docs · Read the API docs

FAQ

  • We already have a DBS integration. What would Acme add?

    Acme adds the banks, markets and capabilities you don't have yet, such as payouts, collections, virtual accounts, FX and real-time transaction feeds, on top of what you run today, all through one REST API. We run the bank onboarding and paperwork, build each connection and test every bank and currency pair before go-live. More than 40 clients are already live with DBS through Acme, so we know its channels well.

  • Does Acme ever hold or move our funds?

    No. Acme is a non-regulated technology layer, not a bank, and never holds funds. Payments move directly between your bank account and your counterparty's bank; Acme sends the instruction and returns the status. Your accounts and bank relationships stay in your name, and you keep full ownership of your bank credentials.

  • How long does it take to go live with a new bank?

    Typically 6–8 weeks, compared with 6–10 months for an in-house build. In that time we run the project and paperwork with the bank, build the connection behind our API, test every bank and currency pair, and move you to production. Your engineers can start building straight away in test mode, which uses a test API key, doesn't affect live data and doesn't interact with any bank.

  • What happens when a bank changes its API, file format or moves to ISO 20022?

    We absorb it on our side, at no extra cost. Bank format changes, upgrades, credential rotation and ISO 20022 / CBPR+ migrations are part of the service, so you don't rebuild anything when a bank changes. For example, we shielded a client through Standard Chartered's core-banking upgrade. Our own API is versioned (/v1) and backward compatible: we don't remove endpoints without notice or add new required fields to existing ones.

  • Should we integrate through your REST API or through our ERP?

    It depends on who will use the data. Build on the REST API if your engineers want full control over payments, collections and bank feeds inside your own systems. If finance works in NetSuite or Microsoft Business Central, install our app for bank feeds and bill payments with no code, and our SI partner Lancia Consult can handle the ERP set-up. Acme is the only NetSuite bank-connectivity layer in Singapore.

  • Which banks, markets and payment rails do you cover?

    Our deepest coverage is in Singapore and South-East Asia, where more than 40 clients are live with DBS across eGIRO, PayNow and full payment stacks. We connect to 25 banks, including CIMB, Citibank, DBS, HSBC, OCBC, RHB, Standard Chartered, UOB, ANZ, Deutsche Bank and Zand, across markets such as Hong Kong, Malaysia, Australia, the UAE and the UK. Supported rails and required fields vary by bank. If yours isn't listed, we build it.

  • How is the connection between our systems, Acme and the bank secured?

    Every hop is encrypted and authenticated. Your systems call Acme over TLS 1.2/1.3 with scoped API keys, which we store hashed and can restrict to your IP addresses. Webhooks are signed with HMAC-SHA256 so you can verify they came from Acme. Bank connections use mTLS, PGP or X.509 as each bank requires, and bank credentials are encrypted and stored separately per customer per bank. Acme is ISO 27001:2022 certified and hosted on AWS Singapore.

  • Ready to connect every bank in weeks?