Quickstart
Ten minutes from registration to a verified, signed API call. Complete this before writing integration code — it isolates credential and signing problems from everything else.
- Register and create an app
Sign up at open.mallplus.ph/partner/register, verify your email, complete your developer profile, then create an app. You will receive a sandbox
client_idandclient_secret.The secret is shown once. Store it in your secret manager immediately. If you lose it, rotate via
POST /open/v1/credentials/rotate-secret— the old secret dies instantly. - Confirm which host your credential belongs to
Sandbox and production are separate hosts, each with its own credential kind. On production, a sandbox
mp_…credential (and vice-versa) returns401 INVALID_CREDENTIALS— a common first-call slip. Always pair the credential with its own host.Credential Base URL mp_… https://sandbox.open.mallplus.ph mp_live_… https://open.mallplus.ph - Sign your first request
GET /open/v1/usagereturns your own app's call statistics. It needs no seller authorization, so it verifies your signing in isolation.// Node 18+ — no dependencies import crypto from 'node:crypto'; const clientId = 'mp_REPLACE_WITH_YOUR_CLIENT_ID'; const clientSecret = 'REPLACE_WITH_YOUR_CLIENT_SECRET'; const baseUrl = 'https://sandbox.open.mallplus.ph'; const method = 'GET'; const path = '/open/v1/usage'; const query = ''; // canonical query string — see Authentication const body = ''; // empty for GET const timestamp = Math.floor(Date.now() / 1000).toString(); const nonce = crypto.randomBytes(16).toString('hex'); const bodyHash = crypto.createHash('sha256').update(body).digest('hex'); const baseString = [timestamp, clientId, method, path, query, bodyHash, nonce].join(':'); const signature = crypto.createHmac('sha256', clientSecret).update(baseString).digest('hex'); const res = await fetch(baseUrl + path, { headers: { 'X-MallPlus-Partner-Id': clientId, 'X-MallPlus-Timestamp': timestamp, 'X-MallPlus-Signature-Version': '3', 'X-MallPlus-Nonce': nonce, 'X-MallPlus-Signature': signature } }); console.log(res.status, await res.json()); - Verify the result
A correct call returns HTTP 200 with this shape (a brand-new app reports zeros):
{ "success": true, "data": { "summary": { "totalCalls": 0, "successCalls": 0, "failCalls": 0, "successRate": 0 }, "endpoints": [], "quota": { "window": "per_minute", "limit": 600, "used": 1, "remaining": 599, "resetAt": "2026-08-15T09:31:00.000Z" } } }If you did not get a 200, match the code below. Do not proceed until this call succeeds.
Code Cause Fix 401 INVALID_CREDENTIALS Credential kind does not match the host Use the sandbox host with mp_…, production withmp_live_…401 INVALID_SIGNATURE Base string or secret mismatch, or uppercase hex Print your base string and compare field-by-field with Authentication 401 TIMESTAMP_EXPIRED Clock drift > 90s, or milliseconds sent Send seconds; sync via NTP 400 MISSING_NONCE X-MallPlus-NonceomittedRequired whenever signature version is 3 400 INVALID_NONCE Nonce is not 32–64 lowercase hex randomBytes(16).toString('hex')403 FORBIDDEN App not active, or missing scope Check app status and granted scopes in the console - Connect a seller
Everything beyond
/usage,/logsand/credentialsacts on a seller's data and needs their authorization. Follow Seller authorization to obtain an access token, then send it asX-MallPlus-Access-TokenalongsideX-MallPlus-Seller-Id. - Subscribe to webhooks
Order intake is webhook-driven. Create a subscription for
order.createdbefore you build any polling logic — see Webhooks.