A small API you can finish in a sprint.
Create a payment, send the user to its payment screen and credit the order when a signed event arrives. The full reference is available to approved merchant accounts.
Endpoints
| Method | Path | What it does |
|---|---|---|
| POST | /v1/payments | Create a payment and get its payment screen URL |
| GET | /v1/payments/{id} | Retrieve a payment and its current status |
| GET | /v1/payments | List payments, filtered by status, date or order ID |
| POST | /v1/events/{id}/redeliver | Send a webhook event again |
Ship it with one API call and one webhook.
Create a payment from your server, send the user to the payment screen it returns, and credit the order when a signed payment.completed event arrives. Voucher handling, receipt confirmation and retries stay on our side.
One payment, from request to settlement record
Hover to pause · select a step
POST /v1/paymentsIdempotency-Key: ORD-58211-1{"orderId": "ORD-58211","customerId": "u_2210","amount": 55000,"currency": "KRW","returnUrl": "https://example.com/orders/ORD-58211"}
{ "id": "pay_6nHs4ZpC8q", "status": "pending","payUrl": "https://pay.marupay.app/p/6nHs4ZpC8q" }
What your team builds
A server call that creates a payment
POST /v1/paymentsThe response carries the payment screen URL. Send your user there, and they come back to your service when they're done.
A webhook endpoint that credits the order
payment.completedWhen a payment completes, a signed event arrives. Verify it, then complete the purchase on your side.
Receipt confirmation, matching, retries and settlement records run on MaruPay.
The full reference is available to approved merchant accounts.
create-payment.sh
curl https://api.marupay.app/v1/payments \
-H "Authorization: Bearer mp_live_••••••••" \
-H "Idempotency-Key: ORD-58202-1" \
-H "Content-Type: application/json" \
-d '{
"orderId": "ORD-58202",
"customerId": "u_6624",
"amount": 49500,
"currency": "KRW",
"returnUrl": "https://example.com/orders/ORD-58202"
}'
HTTP/1.1 201 Created
{
"data": {
"id": "pay_2MzV6hTf9w",
"orderId": "ORD-58202",
"amount": 49500,
"currency": "KRW",
"status": "pending",
"payUrl": "https://pay.marupay.app/p/2MzV6hTf9w",
"expiresAt": "2026-09-29T05:01:58Z"
}
}
webhook.http
POST /webhooks/marupay HTTP/1.1
Host: api.example.com
Content-Type: application/json
MaruPay-Event-Id: evt_5hRd0Xw8Ne
MaruPay-Signature: t=1790656319,v1=e2c97b…0f5a
{
"id": "evt_5hRd0Xw8Ne",
"type": "payment.completed",
"data": {
"paymentId": "pay_2MzV6hTf9w",
"orderId": "ORD-58202",
"amount": 49500,
"currency": "KRW",
"completedAt": "2026-09-29T04:31:58Z"
}
}
HTTP/1.1 200 OK
verify.ts
import crypto from "node:crypto";
// header: "t=<unix>,v1=<hex>" body: the raw request body
export function verify(body: string, header: string, secret: string) {
const [, t, v1] = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(header) ?? [];
if (!t || !v1) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${body}`)
.digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(t)) <= 300;
return fresh && crypto.timingSafeEqual(
Buffer.from(v1, "hex"),
Buffer.from(expected, "hex"),
);
}
// Retried deliveries reuse the event ID: credit each one once.
if (await processed.has(event.id)) return res.status(200).end();
Conventions
Idempotency-Key
Required on create. The same key and body replays the original response.
Amounts
Integers in KRW. No decimals, no currency conversion.
Timestamps
ISO 8601 in UTC in the API; the console shows your time zone.
Keys
mp_test_ and mp_live_ keys, scoped to one merchant account.
Live payments open after the integration test.
You'll know your integration works before real money moves. The test runs your handler through completion, retries, duplicates and review cases, and live payments open once it passes.
Talk to salesContact
Tell us about your service and your Korean users.
Review
We confirm merchant conditions and set up your console account.
Integrate
Create payments, handle webhooks and verify signatures against the docs.
Pass the integration test
Run the required scenarios in test mode.
- Completion
- Retries
- Duplicates
- Review cases
Go live
Live payments open, and the console records every payment from the first one.
Locked until the test passes
Get test keys.
Tell us about your service and we'll set up a test account for your team.