mpac-pgw API Reference
Base URL: https://pgw.example.com (production) / http://localhost:8080 (development)
Authentication
HMAC-SHA256 (Server-to-Server)
Used for: Create, List, Capture, Sync endpoints.
Authorization: HMAC-SHA256 <api_key>:<timestamp>:<signature>
Message = METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + HEX(SHA256(BODY))
Key = bytes(HEX(SHA256(secret_key)))
Signature = HEX(HMAC-SHA256(Key, Message))The HMAC key is the byte representation of the hex-encoded SHA-256 of the secret key (64 ASCII bytes), matching the
secret_key_hashcolumn in the database.
Timestamp window: 5 minutes.
payment_token (Client/Frontend)
Used for: Retrieve, Confirm, Cancel endpoints.
- GET:
?payment_token=<token> - POST:
{ "payment_token": "<token>" }in request body
Endpoints
Health Check
GET /healthReturns service health status. No authentication required.
Response:
{
"status": "ok"
}Create PaymentIntent
POST /v1/payment_intentsAuth: HMAC-SHA256
Request Body:
{
"amount": 1000,
"currency": "JPY",
"payment_method_types": ["qr_mpm"],
"merchant_ref_id": "order_12345",
"merchant_store_id": "store_001",
"merchant_terminal_id": "terminal_001",
"description": "Order #12345",
"expires_in_minutes": 30
}| Field | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Payment amount in smallest currency unit |
currency | string | Yes | ISO 4217 currency code (e.g., JPY) |
payment_method_types | string[] | Yes | Allowed payment methods |
merchant_ref_id | string | Yes | Merchant's order reference |
merchant_store_id | string | No | Store identifier |
merchant_terminal_id | string | No | Terminal identifier |
description | string | No | Human-readable description |
expires_in_minutes | integer | No | Expiry time (default: 30) |
Response (201):
{
"id": "pi_01JXXXXXXXXXXXXXXXXXXXXXXXXX",
"status": "requires_payment_method",
"amount": 1000,
"currency": "JPY",
"payment_method_types": ["qr_mpm"],
"merchant_ref_id": "order_12345",
"merchant_store_id": "store_001",
"payment_token": "pi_01JX..._secret_abc123def456",
"created_at": "2026-01-15T10:00:00Z",
"expires_at": "2026-01-15T10:30:00Z"
}List PaymentIntents
GET /v1/payment_intentsAuth: HMAC-SHA256
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
merchant_store_id | string | Filter by store |
status | string | Filter by status |
limit | integer | Max results (default: 20, max: 100) |
offset | integer | Pagination offset |
Response (200):
[
{
"id": "pi_01JXXXXXXXXXXXXXXXXXXXXXXXXX",
"status": "succeeded",
"amount": 1000,
"currency": "JPY",
...
}
]Retrieve PaymentIntent
GET /v1/payment_intents/:idAuth: payment_token (query parameter)
Response (200):
{
"id": "pi_01JXXXXXXXXXXXXXXXXXXXXXXXXX",
"status": "requires_payment_method",
"amount": 1000,
"currency": "JPY",
"payment_method_types": ["qr_mpm"],
"merchant_ref_id": "order_12345",
"created_at": "2026-01-15T10:00:00Z",
"expires_at": "2026-01-15T10:30:00Z"
}Confirm PaymentIntent
POST /v1/payment_intents/:id/confirmAuth: payment_token (in body)
Request Body:
{
"payment_token": "pi_01JX..._secret_abc123def456",
"payment_method_type": "qr_mpm",
"provider": "PAYPAY"
}Response (200):
{
"payment_id": "pi_01JXXXXXXXXXXXXXXXXXXXXXXXXX",
"qr_content": "https://qr.paypay.ne.jp/...",
"expires_at": "2026-01-15T10:05:00Z",
"provider": "PAYPAY"
}Cancel PaymentIntent
POST /v1/payment_intents/:id/cancelAuth: payment_token (in body)
Request Body:
{
"payment_token": "pi_01JX..._secret_abc123def456"
}Response (200):
{
"id": "pi_01JXXXXXXXXXXXXXXXXXXXXXXXXX",
"status": "cancelled"
}Capture PaymentIntent
POST /v1/payment_intents/:id/captureAuth: HMAC-SHA256
Used for manual processing mode (e.g., cash payments confirmed by staff).
Request Body:
{
"amount": 1000
}Response (200):
{
"id": "pi_01JXXXXXXXXXXXXXXXXXXXXXXXXX",
"status": "succeeded",
"amount": 1000,
"currency": "JPY"
}Sync Merchants
POST /v1/sync/merchantsAuth: HMAC-SHA256
Synchronizes merchant and store data from the upstream system. Uses UPSERT semantics.
Request Body:
{
"merchants": [
{
"id": "merchant_001",
"name": "Example Restaurant Chain",
"stores": [
{
"id": "store_001",
"name": "Tokyo Branch",
"payment_processor_configs": [
{
"provider": "PAYPAY",
"is_active": true,
"credentials": {
"merchant_id": "paypay_merchant_123"
}
}
]
}
]
}
]
}Response (200):
{
"synced_merchants": 1,
"synced_stores": 1
}Webhooks
PayPay Webhook
POST /v1/webhooks/paypayReceives payment status updates from PayPay. Authenticated via PayPay's webhook signature.
Error Responses
All error responses follow a consistent format:
{
"code": "invalid_request",
"message": "Amount must be greater than 0",
"details": {
"field": "amount",
"constraint": "min_value"
}
}Common Error Codes
| HTTP Status | Code | Description |
|---|---|---|
| 400 | invalid_request | Request validation failed |
| 401 | unauthorized | Missing or invalid authentication |
| 401 | invalid_token | Payment token is invalid or expired |
| 403 | forbidden | Insufficient permissions |
| 404 | not_found | Resource not found |
| 409 | idempotency_conflict | Conflicting idempotent request |
| 429 | rate_limit_exceeded | Rate limit exceeded |
| 500 | internal_error | Server error |
Rate Limiting
| Scope | Limit |
|---|---|
| Per merchant | 1,000 requests/minute |
| Global | 10,000 requests/minute |
Rate limit headers are included in all responses:
X-RateLimit-Limit: Maximum requests allowedX-RateLimit-Remaining: Remaining requests in windowX-RateLimit-Reset: Unix timestamp when window resets
Idempotency
POST requests support idempotency via the Idempotency-Key header. Keys are cached for 24 hours.
Idempotency-Key: unique-request-id-12345If a duplicate key is received within the retention window, the original response is returned without re-executing the operation.