Skip to main content

API overview

This reference covers the server-to-server integration API available to environment-bound API keys. Interactive dashboard and platform-operator operations are intentionally excluded.

Base URLhttps://pehmen-api.huper.technology
Version headerpehmen-version: 2026-08-01 on every response. Sending a different Pehmen-Version is a 400.
ReferenceGET /openapi.json (OpenAPI 3.1) and GET /docs (rendered), generated at boot from the live route table.
LivenessGET /healthz → {"ok":true,"service":"pehmen-api"}
Public keysGET /.well-known/pehmen-webhook-keys.json, GET /.well-known/pehmen-vce-keys.json

Headers​

HeaderMeaning
x-api-key: pehmen_test_… or Authorization: Bearer pehmen_test_…Your key.
x-pehmen-organization: <workspace id>The workspace, as a 36-character UUID, shown on the overview and Quickstart screens. The API verifies that it matches the key's workspace.
x-pehmen-environment: testDefaults to test. A key may only name its own environment (403 environment_mismatch).
idempotency-key: <1–255 chars>Mandatory where the operation's OpenAPI parameters mark it required.
content-type: application/jsonOn bodies. Body limit 1 MiB.

Every response carries request-id (minted server-side, never adopted from the request). Quote it when you ask for help.

Idempotency​

The key is scoped to workspace, environment and resource family. The request is fingerprinted (method, URL, body):

  • Same key, same request: the stored response is replayed. Nothing re-runs.
  • Same key, different request: 409 idempotency_conflict.
  • Same key while the first is still running: 409 idempotency_in_progress.
  • Missing or too long: 400 idempotency_key_required.

Use something you already have, like your order id, so a retry after a timeout can never create a second payment.

Money and ids​

Amounts are integer minor units with an ISO 4217 currency (12800 + SGD is SGD 128.00). A value already rounded by JSON parsing is refused rather than paid.

Ids are prefix_ + 32 lowercase hex: org_, usr_, mct_, con_, ord_, pi_, pa_, ptx_, rd_, rk_, re_, slr_, bnf_, bch_, po_, cs_, ev_, evt_ (the id in Pehmen-Event-Id), apl_, pol_, whe_, whd_, whi_, rcf_, rcx_, key_, apr_, sim_, vce_, fev_, fsrc_, job_, att_, mcu_, nch_, dxi_. The workspace id used in the x-pehmen-organization header is the exception: a plain UUID.

Lists​

GET lists take limit (up to 200) and after (a cursor). Responses are { data: [...], has_more, next_cursor }.

Errors​

One envelope everywhere, including unmatched routes:

{ "error": { "code": "no_eligible_route", "message": "…", "request_id": "…", "details": [ … ] } }

Codes and their meanings are in Errors. A refused credential carries details: [{ reason_code, guidance }] with the same operator guidance the dashboard shows.

Cross-workspace access​

An object that belongs to another workspace is a 404, indistinguishable from one that does not exist.

Rate limits​

LimiterNumbers
Per API keyBucket of 50, refilled at 10 per second. 429 rate_limited.
Mutations per source IP600 per minute, burst 900. 429 with retry-after.
Provider webhook inbox per IP3000 per minute, burst 4500.