1. Agree the business, owner and minimum access
The business needs API access through its POS Connect entitlement (Scale, Enterprise or Franchise, including an eligible active trial). If key creation is unavailable, ask the owner to check the plan and your permissions; do not borrow another business’s key. The business owner creates the key in Settings → API keys → Create API key. Select Test and only Enrolments: read (ENROLLMENTS_READ) and
Transactions: write (TRANSACTIONS_WRITE). No customer-write, enrolment-write,
webhook-write or broad read-only preset is needed.
Name it for the system and responsible maintainer, such as Till setup — Alex.
Set an expiry covering the agreed test period; revoke it when testing ends.
The business owns the key and can revoke it. The developer owns its secure
storage and the receiving server. Perkstar cannot show the full key again.
Keep the secret in a private file named .perkstar-test.env, excluded from
source control. Set restrictive file permissions (for example chmod 600 .perkstar-test.env on macOS/Linux). Do not put it in browser code, screenshots,
support messages or a shell command that will remain in history.
organization.id, not the six-digit account
number in the dashboard URL. Read GET /marketplace/ping with the test key to
check the business and its active cards. Read GET /enrollments?cardId=<id> to
find the agreed enrolment; follow next_cursor if necessary. Inspect these
responses privately. Never select the first business or enrolment automatically.
The script verifies the business, test mode, scopes, active stamp card and
matching active enrolment before writing.
2. Download, inspect and run the example
Use Node.js 24 or later. There are no packages to install. Download pos-test-quickstart.mjs Save the file, inspect it, then run:POST /transactions and the receipt ID as Idempotency-Key. This
example is for a completed sale earning one stamp, not a spend-to-stamp or
points calculation. Use the POS guide for those workflows.
Amounts named amount_pence use the business currency’s minor units; never
assume every currency uses two decimal places.
3. Check the result, repeat and exercise an error
The script runs all five checks and prints a compact
PASS summary without
customer records or secrets. Run it again with the same receipt ID: it
should identify the same transaction. Each genuinely new sale needs its own
namespaced permanent reference. Do not generate a new reference on every retry.
A real customer being served during the check may change their balance through
another channel. That is why an isolated test enrolment is useful. A successful
script proves this small API workflow, not every card type or POS feature.
4. Receive a signed test event
Download test-webhook-receiver.mjs The receiver acceptstransaction.created only when data.testMode is true,
plus the dashboard’s synthetic webhook.test. It validates the signature,
five-minute signing timestamp and business ID, then commits a minimal receipt
to a local SQLite file before returning 200. It stores the delivery ID, event
type, transaction ID, time and a content hash; it does not store the full customer
payload, award another stamp or claim to fulfil an order.
Add the separate webhook signing secret to the private environment file:
127.0.0.1:8787/webhooks/perkstar. Perkstar cannot deliver to your
localhost. Expose that exact path through an HTTPS ingress you control, then ask
the business owner to create a separate test endpoint in Settings →
Webhooks, subscribed to transaction.created, filtered to the selected card
and Test mode. The API test key cannot change webhook configuration. Keep
the existing production endpoints intact. Store the one-time signing secret in
the receiver’s private configuration before testing delivery.
Use Send test to check connectivity. Then run the POS script with a new test
receipt to check a real test-transaction event. Check the endpoint’s delivery
history and your receiver’s receipt; webhook dispatch is asynchronous.
The database file must survive restarts. Do not deploy this teaching receiver on
an ephemeral filesystem. Before production, use a durable inbox/queue shared by
all instances, process real business work asynchronously and make downstream
operations idempotent too. Do not simply remove the live-event rejection.
Node’s built-in SQLite module may show an experimental warning on earlier Node
24 releases; see the Node SQLite documentation.
If a check fails
- 401: the key may be wrong or expired. Ask its owner to replace it; do not print the secret while diagnosing it.
- 410: the key has been revoked. Stop using it and ask its owner for a replacement.
- 403: check the selected scopes and business access. Add only the missing permission needed for the intended operation.
- 404: verify the enrolment belongs to the chosen business/card.
- 409: check reused request keys and receipt references. Changing a payload is not a retry of the original operation.
- 429: wait for
Retry-Afterbefore rerunning with the same receipt ID. - Timeout/5xx: the write may have succeeded. Keep the receipt ID unchanged, inspect the outcome and use a bounded retry policy; never loop indefinitely.
- Webhook 307/308: enter the final HTTPS destination directly. Perkstar does not follow redirects; confirm the exact route accepts POST.
- Webhook timeout/5xx: fix storage/availability and acknowledge promptly after persistence. Resend an exhausted delivery only after correcting the receiver.

