← PEAK integration

Connecting a PEAK business

The three credentials

A PEAK connection needs three values, and they come from two different places.

Connect ID and Connect Key identify you, the system calling the API. PEAK issues them; there is no self-serve key page. Email puriwat.vu@peakengine.com, cc pafan.ch@peakengine.com, with your business name, the document flow you want to automate (POS to invoice, say), your estimated monthly transaction volume, and a developer contact. They answer in one to two business days with UAT credentials, delivered as an encrypted ZIP from notification@peakengine.com.

User Token identifies which business you act on. The account owner generates it in the PEAK app, and that part is self-serve.

One Connect ID serves every business you connect. One User Token serves exactly one business and one user inside it — tokens are not swappable, so a second business means a second connection.

Generating the User Token

Sign in at secure.peakaccount.com, pick the business, then: ตั้งค่า → ตั้งค่าเชื่อมต่อระบบภายนอก → เชื่อมต่อแอปพลิเคชันภายนอก → เชื่อมต่อแอปพลิเคชันของคุณ. Paste the Application Code, confirm the application name, accept the terms, connect. The token appears on the connection detail page behind an eye icon.

The Application Code is the piece people trip on. It arrives in a second email, separate from the credential ZIP, and it is not a credential — you never send it to the API. Its only job is to let the merchant mint a User Token against your Connect ID. Repeat the flow with the same code to mint more.

UAT and production are separate worlds

The UAT credentials are not production credentials, and mixing a pair with the wrong host fails in ways that read like a broken integration. Production credentials are issued only after the commercial terms are settled — you confirm the API package and transaction limits with PEAK, send payment evidence, and they release the production pair, usually within a day or two.

Which package a business needs

PEAK's own MCP connector requires PRO Plus or above, and on a lower package the "เชื่อมต่อ MCP" button simply does not render. The REST Open API we use here is gated commercially rather than by that button, so the package question is one to settle in the same email thread rather than assume either way.

How a call is signed

Every request carries four headers: Client-Token, User-Token, Time-Stamp and Time-Signature. The timestamp is UTC+0 as yyyyMMddHHmmss. The signature is HMAC-SHA1 of that timestamp, keyed by the Connect ID.

PEAK never says whether the signature is base64 or hex. We send base64 and, if the client-token mint is rejected, flip to hex and mint again. If your account settles on one encoding, that fallback is dead weight worth deleting.

The Client-Token itself is minted from the Connect ID and Key, lives 24 hours, and is cached on the account asset — minting is capped at ten requests a minute, so it is not something to do per call.

Failures hide in the body

PEAK answers HTTP 200 and puts the verdict in resCode inside the response envelope. A call that "succeeded" with resCode: "403" and resDesc: "lock by period" did nothing — that one means the accounting period is closed and the document cannot be written. Never trust the status line alone.

Two recurring ones worth naming: lock by period, above, and **transaction cannot void**, which means the document has downstream references (a receipt against an invoice, say) that must be voided first.

Limits and credits

Ten GET and five POST requests may be in flight per User Token; over the line PEAK returns 429 with retryAfterSeconds, or null for that field when the breach was concurrency rather than rate. File uploads are capped at two a minute.

Separately, calls are metered against a monthly credit balance with free, prepaid and postpaid tiers — peak_get_api_credit reads it. This is a real budget, not a formality: a nightly sweep that re-reads every document burns credits a date-ranged list call would not.

Dates and money

Dates are yyyyMMdd strings, not ISO timestamps. Amounts are Thai baht, and the field to read for "what is still owed" is remainAmount rather than netAmount.