Referenz
Referenz der POS-API
Die POS Posting API ist eine eigene, bestehende Schnittstelle für Kassensysteme: Sie bucht Restaurant-, Bar- oder Shopposten auf das Konto eines eingecheckten Aufenthalts. Sie verwendet eigene POS-Schlüssel aus den POS-Einstellungen in STRYK, keine Partner-API-Schlüssel.
STRYK POS Posting API Version 1.3.0
Vor der Anbindung
- Diese Referenz beschreibt die direkte API. Sie ist kein zertifizierter Adapter für einen bestimmten Kassenhersteller.
- Es gibt keine öffentliche Sandbox. Stimme einen Testablauf mit dem Hotel ab.
- Die Einrichtung in STRYK Schritt für Schritt beschreibt die POS-Dokumentation.
- Basis-URL
https://app.staystryk.com/api/v1/pos/public- Spezifikation
- OpenAPI, YAML OpenAPI, JSON
Server-to-server interface for posting till items to physically checked-in hotel stays. STRYK issues a hotel-bound Bearer key once at creation; the stored hash cannot be revealed later. This documents the existing direct API, not a certified adapter for any named POS vendor. No public sandbox or automatic vendor onboarding is implied. Unknown optional response fields must be tolerated. The hotel needs the add-on STRYK POS; without it every call answers 403 with code module_disabled (no posting is written).
STRYK implements an inbound REST API with Bearer authentication. Mews similarly offers PMS APIs that a POS calls. Lightspeed K-Series specifies an OAuth-authorized PMS registration and its own callback protocol; that requires a provider-specific adapter, not merely pasting a STRYK key. No named vendor adapter is claimed here. Agree on integration ownership, outlet mapping, tax mapping and acceptance tests with the vendor before configuring a live till.
This interface performs room-account lookup, positive item posting, state recovery and cancellation. It is not a payment-terminal API, cash register, fiscal receipt service, product catalogue sync, stock system or full restaurant sales import. Cash/card payments settled at the till must not also be posted to the room. For split tenders send only the unpaid room portion, with correctly allocated tax and a unique reference per item; reconcile rounding explicitly. No negative-price, zero-price, discount, tip or refund endpoint exists. Apply item discounts before posting positive gross prices; financial corrections use the controlled cancellation or invoice workflow.
Create the sales outlet with an active central tax, grant POS management only to authorized staff and issue one appropriately scoped key per connection. /ping only confirms key authentication; verify a controlled room posting before go-live. Use the live /accounts result or /room-lookup, show guest and room for confirmation, and send bookingId plus room. Do not persist the account list as an indefinite guest directory. No-Post, available credit, account closure, actual check-in/out and room segments are validated again when writing. Departure-day postings are allowed while the guest remains checked in; post-checkout imports are rejected.
Use JSON numbers in hotel currency, positive gross unit prices, decimal arithmetic, quantity rounded HALF_UP to 3 decimals and money to 2. Maximum quantity 9999, unit price 99999.99, gross item total 99999999.99. Tax must be an active configured rate on the service date; omission resolves outlet/central defaults. Hotel timezone determines service dates. Freeze chargedAt and the complete request before first transmission. Never recalculate timestamps, prices, tax or references on retry.
Persist outgoing requests locally on the POS server before sending. An externalRef belongs to hotel + API key, not the whole hotel. Exact POST replay returns 201, including an already transferred original item; cancelled references and changed payloads return 409. On timeout or 5xx first query the original reference. Only a confirmed 404 permits resending the same request with the same key. Check every line after an uncertain batch. If a member of staff manually posted the receipt during an outage, reconcile it before replay; posRef can assist but does not deduplicate. A new key creates a different idempotency scope and cannot look up/cancel the old key’s charges. Drain and reconcile outstanding work before revoking an old key. If it is lost or compromised, revoke it and resolve uncertain transactions in STRYK before submitting any replacements.
400: fix invalid fields; 401: authentication could not be validated; 403: scope not allowed; 404: account/item absent; 409: business conflict (inspect code, do not blindly retry); 429: rate limit, wait at least 60 seconds; 5xx/network error: bounded backoff, state reconciliation and visible operator escalation. error contains human-readable text; code and requestId are optional. Never branch on German text or invent a new reference to bypass a failure. Any unlisted 5xx is also a service failure, never success.
POST creates an open charge; it does not record payment. Checkout invoice generation transfers open charges into invoice positions. The API then returns status=transferred. Those items cannot be cancelled by the POS API; correct the invoice through STRYK Finance. Cancellation leaves an auditable cancelled charge. State lookup and cancellation cannot access another key’s items, even in the same hotel. General POS exports are available through the module statistics in STRYK.
Configure an HTTPS target and a separate secret in POS Setup. Outbound POSTs use JSON and User-Agent STRYK-POS-Webhook/1.0. X-STRYK-Event is charge.posted or charge.cancelled; a manual connection test uses ping. X-STRYK-Webhook-Id is the subscription UUID, not an event or delivery ID. X-STRYK-Signature is sha256=<hex HMAC of exact UTF-8 request bytes> only when a secret is configured. Reject unsigned requests when expecting signed delivery. Persistently deduplicate event + data.chargeId (and hotelId where shared). Timestamp is generated per attempt, not a stable deduplication key. Deliveries may repeat or arrive out of order; do not let an old posted event overwrite cancellation. Respond 2xx only after durable acceptance, within 10 seconds; redirects are not followed. Failed deliveries enter the durable retry queue with delays of 30 seconds, 5 minutes, 30 minutes, then 2 hours, up to the stored attempt limit. Exhausted delivery state is visible in STRYK and needs operator reconciliation. There is no invoice-transfer or check-in/out webhook in this contract; re-read account/charge state as needed.
Use an explicitly approved test hotel and real in-house test stay. Check ping, guest/room identity, multi-room booking selection, scoped outlet rejection, configured tax and currency, exact retry without a duplicate, changed-payload 409, lost response recovery, batch all-or-none, No-Post and credit-limit rejection, cancellation replay, checkout invoice totals and transferred cancellation rejection. Verify a signed webhook, invalid signature rejection and duplicate/out-of-order delivery. Confirm error visibility, key rotation and staff reconciliation before release. Do not execute these tests against unrelated guest stays.
7 Endpunkte
Endpunkte
GET/pingCheck the connection
/pingCheck the connectionScopes: Jeder gültige SchlüsseloperationId pingPosConnection
Antworten
200Connection accepted
application/jsonstatusstringPflicht
{ "status": "ok" }400Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }401Key could not be validated (missing, invalid, revoked, or verification unavailable). Check configuration and service status; do not automatically rotate credentials or replay under a new key.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }429100 requests per 60-second window per key, shared across application instances. No Retry-After header is currently returned. Wait at least 60 seconds, then retry with backoff and jitter. Reconcile uncertain writes before retrying.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }500Unexpected service error. A failed or lost response is not proof that a write was rolled back. Reconcile GET /charges/{externalRef} before retrying with the original key and request. Back off for transient 5xx and network failures. Escalate persistent errors with requestId; never change reference to bypass an error.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }
curl 'https://app.staystryk.com/api/v1/pos/public/ping' \
-H "Authorization: Bearer $STRYK_POS_API_KEY"const response = await fetch('https://app.staystryk.com/api/v1/pos/public/ping', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.STRYK_POS_API_KEY}`,
},
});
if (!response.ok) {
const problem = await response.json();
throw new Error(`${problem.code}: ${problem.detail} (request ${problem.requestId})`);
}
const data = await response.json();import os
import requests
response = requests.get(
"https://app.staystryk.com/api/v1/pos/public/ping",
headers={
"Authorization": f"Bearer {os.environ['STRYK_POS_API_KEY']}",
},
timeout=30,
)
response.raise_for_status()
data = response.json(){
"status": "ok"
}GET/accountsList currently checked-in room accounts
/accountsList currently checked-in room accountsScopes: Jeder gültige SchlüsseloperationId listChargeableAccounts
Antworten
200Current in-house accounts, including No-Post and limit state
application/jsonbookingIdstring (uuid)PflichtbookingNumberstringPflichtguestNamestringPflichtroomNumberstringPflichtallowPostingbooleanPflichtHotel No-Post policy. true alone does not imply a charge is permitted.
allowChargebooleanPflichtCombined eligibility, taking policy, available credit and closed invoice account into account.
accountClosedbooleanPflichtpostingBlockReasonstring | nullWerte:
"no_post","credit_limit_reached","account_closed",nullopenChargesCountintegerPflichtopenChargesTotalnumberPflichtstayChargesTotalnumberPflichtNon-cancelled stay charges, including transferred items. Credit policy uses this cumulative total.
creditLimitnumber | nullremainingCreditnumber | nullcurrencystringPflicht
[ { "bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "bookingNumber": "string", "guestName": "string", "roomNumber": "string", "allowPosting": true, "allowCharge": true, "accountClosed": true, "postingBlockReason": "no_post", "openChargesCount": 0, "openChargesTotal": 1.5, "stayChargesTotal": 1.5, "creditLimit": 1.5, "remainingCredit": 1.5, "currency": "string" } ]400Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }401Key could not be validated (missing, invalid, revoked, or verification unavailable). Check configuration and service status; do not automatically rotate credentials or replay under a new key.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }429100 requests per 60-second window per key, shared across application instances. No Retry-After header is currently returned. Wait at least 60 seconds, then retry with backoff and jitter. Reconcile uncertain writes before retrying.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }500Unexpected service error. A failed or lost response is not proof that a write was rolled back. Reconcile GET /charges/{externalRef} before retrying with the original key and request. Back off for transient 5xx and network failures. Escalate persistent errors with requestId; never change reference to bypass an error.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }
curl 'https://app.staystryk.com/api/v1/pos/public/accounts' \
-H "Authorization: Bearer $STRYK_POS_API_KEY"const response = await fetch('https://app.staystryk.com/api/v1/pos/public/accounts', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.STRYK_POS_API_KEY}`,
},
});
if (!response.ok) {
const problem = await response.json();
throw new Error(`${problem.code}: ${problem.detail} (request ${problem.requestId})`);
}
const data = await response.json();import os
import requests
response = requests.get(
"https://app.staystryk.com/api/v1/pos/public/accounts",
headers={
"Authorization": f"Bearer {os.environ['STRYK_POS_API_KEY']}",
},
timeout=30,
)
response.raise_for_status()
data = response.json()[
{
"bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"bookingNumber": "string",
"guestName": "string",
"roomNumber": "string",
"allowPosting": true,
"allowCharge": true,
"accountClosed": true,
"postingBlockReason": "no_post",
"openChargesCount": 0,
"openChargesTotal": 1.5,
"stayChargesTotal": 1.5,
"creditLimit": 1.5,
"remainingCredit": 1.5,
"currency": "string"
}
]GET/room-lookupResolve a checked-in stay by room number
/room-lookupResolve a checked-in stay by room number404 when no eligible current occupant exists. 409 when the room lookup is ambiguous. Never guess a guest from a room label or silently select the first match.
Scopes: Jeder gültige SchlüsseloperationId lookupRoomAccount
Parameter, query
| Name | Ort | Typ | Beschreibung |
|---|---|---|---|
roomPflicht | query | string | - |
Antworten
200Unique current room account
application/jsonbookingIdstring (uuid)PflichtbookingNumberstringPflichtguestNamestringPflichtroomNumberstringPflichtallowPostingbooleanPflichtHotel No-Post policy. true alone does not imply a charge is permitted.
allowChargebooleanPflichtCombined eligibility, taking policy, available credit and closed invoice account into account.
accountClosedbooleanPflichtpostingBlockReasonstring | nullWerte:
"no_post","credit_limit_reached","account_closed",nullopenChargesCountintegerPflichtopenChargesTotalnumberPflichtstayChargesTotalnumberPflichtNon-cancelled stay charges, including transferred items. Credit policy uses this cumulative total.
creditLimitnumber | nullremainingCreditnumber | nullcurrencystringPflicht
{ "bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "bookingNumber": "string", "guestName": "string", "roomNumber": "string", "allowPosting": true, "allowCharge": true, "accountClosed": true, "postingBlockReason": "no_post", "openChargesCount": 0, "openChargesTotal": 1.5, "stayChargesTotal": 1.5, "creditLimit": 1.5, "remainingCredit": 1.5, "currency": "string" }400Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }401Key could not be validated (missing, invalid, revoked, or verification unavailable). Check configuration and service status; do not automatically rotate credentials or replay under a new key.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }404Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }409Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }429100 requests per 60-second window per key, shared across application instances. No Retry-After header is currently returned. Wait at least 60 seconds, then retry with backoff and jitter. Reconcile uncertain writes before retrying.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }500Unexpected service error. A failed or lost response is not proof that a write was rolled back. Reconcile GET /charges/{externalRef} before retrying with the original key and request. Back off for transient 5xx and network failures. Escalate persistent errors with requestId; never change reference to bypass an error.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }
curl 'https://app.staystryk.com/api/v1/pos/public/room-lookup?room=room' \
-H "Authorization: Bearer $STRYK_POS_API_KEY"const response = await fetch('https://app.staystryk.com/api/v1/pos/public/room-lookup?room=room', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.STRYK_POS_API_KEY}`,
},
});
if (!response.ok) {
const problem = await response.json();
throw new Error(`${problem.code}: ${problem.detail} (request ${problem.requestId})`);
}
const data = await response.json();import os
import requests
response = requests.get(
"https://app.staystryk.com/api/v1/pos/public/room-lookup",
headers={
"Authorization": f"Bearer {os.environ['STRYK_POS_API_KEY']}",
},
params={"room": "room"},
timeout=30,
)
response.raise_for_status()
data = response.json(){
"bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"bookingNumber": "string",
"guestName": "string",
"roomNumber": "string",
"allowPosting": true,
"allowCharge": true,
"accountClosed": true,
"postingBlockReason": "no_post",
"openChargesCount": 0,
"openChargesTotal": 1.5,
"stayChargesTotal": 1.5,
"creditLimit": 1.5,
"remainingCredit": 1.5,
"currency": "string"
}POST/chargesPost one item to an in-house account
/chargesPost one item to an in-house accountexternalRef is the immutable idempotency key of this POS connection. An exact retry returns the original charge with idempotentReplay=true. Reusing the reference with changed content or after cancellation returns 409.
Scopes: Jeder gültige SchlüsseloperationId postCharge
Request-Body
bookingIdstring (uuid)Prefer this durable identity together with room; several room segments in one booking require an unambiguous room.
roomstringActual room label, including letters; do not convert to a number. Must match bookingId when both are provided.
outletIdstring (uuid)Optional for an outlet-scoped key (scope is applied automatically). Any supplied value must match the key scope; mismatch is 403. An unrestricted key may choose an outlet.
descriptionstringPflichtquantitynumberDefaults to 1; HALF_UP to 3 decimal places before validation.
unitstringunitPricenumberPflichtGross price per unit, not net. HALF_UP to 2 decimal places before validation. Positive only. Total gross (quantity × unitPrice rounded HALF_UP to 2 places) must be > 0 and <= 99999999.99.
taxRatenumberConfigured active tax on the service date, rounded to 2 decimals. If omitted, use the outlet default, then the central service tax. An unconfigured rate is rejected.
currencystringOptional assertion; must equal the hotel's billing currency.
externalRefstringPflichtStable, trimmed, case-sensitive receipt/item reference owned by the API key. Use URL-safe values (e.g. receipt-123-item-1) so GET/DELETE paths work through proxies. Never reuse for another item or replay under another key.
chargedAtstring (date-time)Optional service timestamp; defaults to now. Prefer ISO-8601 with offset. Legacy local timestamps use the hotel timezone. A time more than 5 minutes ahead is rejected. Service date must match a room segment, and the guest must still be physically in-house when posting. Keep the original timestamp unchanged on retries.
notesstringposRefstringOptional receipt reference for staff reconciliation. It does not replace externalRef and does not provide idempotency.
Antworten
201Created or exact idempotent replay
application/jsonchargeIdstring (uuid)PflichtexternalRefstringPflichtbookingIdstring (uuid)PflichtroomNumberstringPflichtguestNamestringPflichtoutletIdstring (uuid)outletNamestringdescriptionstringPflichtquantitynumberPflichtunitstringunitPricenumberPflichttaxRatenumberPflichtgrossAmountnumberPflichtcurrencystringPflichtstatusstringPflichtWerte:
"open","cancelled","transferred"chargedAtstring (date-time)PflichtcancelledAtstring (date-time)posRefstringidempotentReplaybooleanduplicateWarningobjectAdvisory only: a potentially matching staff-entered item was found. The new charge has ALREADY been posted; reconcile in STRYK, do not resend.
Felder anzeigen (5)
chargeIdstring (uuid)descriptionstringgrossAmountnumberchargedAtstringposRefstring
{ "chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "externalRef": "string", "bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "roomNumber": "string", "guestName": "string", "outletId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "outletName": "string", "description": "string", "quantity": 1.5, "unit": "string", "unitPrice": 1.5, "taxRate": 1.5, "grossAmount": 1.5, "currency": "string", "status": "open", "chargedAt": "2026-11-04T08:15:00.000Z", "cancelledAt": "2026-11-04T08:15:00.000Z", "posRef": "string", "idempotentReplay": false, "duplicateWarning": { "chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "description": "string", "grossAmount": 1.5, "chargedAt": "string", "posRef": "string" } }400Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }401Key could not be validated (missing, invalid, revoked, or verification unavailable). Check configuration and service status; do not automatically rotate credentials or replay under a new key.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }403Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }404Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }409Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }429100 requests per 60-second window per key, shared across application instances. No Retry-After header is currently returned. Wait at least 60 seconds, then retry with backoff and jitter. Reconcile uncertain writes before retrying.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }500Unexpected service error. A failed or lost response is not proof that a write was rolled back. Reconcile GET /charges/{externalRef} before retrying with the original key and request. Back off for transient 5xx and network failures. Escalate persistent errors with requestId; never change reference to bypass an error.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }
curl -X POST 'https://app.staystryk.com/api/v1/pos/public/charges' \
-H "Authorization: Bearer $STRYK_POS_API_KEY"const response = await fetch('https://app.staystryk.com/api/v1/pos/public/charges', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.STRYK_POS_API_KEY}`,
},
});
if (!response.ok) {
const problem = await response.json();
throw new Error(`${problem.code}: ${problem.detail} (request ${problem.requestId})`);
}
const data = await response.json();import os
import requests
response = requests.post(
"https://app.staystryk.com/api/v1/pos/public/charges",
headers={
"Authorization": f"Bearer {os.environ['STRYK_POS_API_KEY']}",
},
timeout=30,
)
response.raise_for_status()
data = response.json(){
"chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"externalRef": "string",
"bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"roomNumber": "string",
"guestName": "string",
"outletId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"outletName": "string",
"description": "string",
"quantity": 1.5,
"unit": "string",
"unitPrice": 1.5,
"taxRate": 1.5,
"grossAmount": 1.5,
"currency": "string",
"status": "open",
"chargedAt": "2026-11-04T08:15:00.000Z",
"cancelledAt": "2026-11-04T08:15:00.000Z",
"posRef": "string",
"idempotentReplay": false,
"duplicateWarning": {
"chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"description": "string",
"grossAmount": 1.5,
"chargedAt": "string",
"posRef": "string"
}
}POST/charges/batchPost up to 50 items atomically
/charges/batchPost up to 50 items atomically1-50 positions, each with its own externalRef; output order matches input. All newly created items commit together or none do. Existing exact replays may appear alongside new items. On uncertain outcome query each original reference before resending the unchanged batch. A conflicting or cancelled reference rejects the batch.
Scopes: Jeder gültige SchlüsseloperationId postChargeBatch
Request-Body
bookingIdstring (uuid)Prefer this durable identity together with room; several room segments in one booking require an unambiguous room.
roomstringActual room label, including letters; do not convert to a number. Must match bookingId when both are provided.
outletIdstring (uuid)Optional for an outlet-scoped key (scope is applied automatically). Any supplied value must match the key scope; mismatch is 403. An unrestricted key may choose an outlet.
descriptionstringPflichtquantitynumberDefaults to 1; HALF_UP to 3 decimal places before validation.
unitstringunitPricenumberPflichtGross price per unit, not net. HALF_UP to 2 decimal places before validation. Positive only. Total gross (quantity × unitPrice rounded HALF_UP to 2 places) must be > 0 and <= 99999999.99.
taxRatenumberConfigured active tax on the service date, rounded to 2 decimals. If omitted, use the outlet default, then the central service tax. An unconfigured rate is rejected.
currencystringOptional assertion; must equal the hotel's billing currency.
externalRefstringPflichtStable, trimmed, case-sensitive receipt/item reference owned by the API key. Use URL-safe values (e.g. receipt-123-item-1) so GET/DELETE paths work through proxies. Never reuse for another item or replay under another key.
chargedAtstring (date-time)Optional service timestamp; defaults to now. Prefer ISO-8601 with offset. Legacy local timestamps use the hotel timezone. A time more than 5 minutes ahead is rejected. Service date must match a room segment, and the guest must still be physically in-house when posting. Keep the original timestamp unchanged on retries.
notesstringposRefstringOptional receipt reference for staff reconciliation. It does not replace externalRef and does not provide idempotency.
Antworten
201Charges in request order
application/jsonchargeIdstring (uuid)PflichtexternalRefstringPflichtbookingIdstring (uuid)PflichtroomNumberstringPflichtguestNamestringPflichtoutletIdstring (uuid)outletNamestringdescriptionstringPflichtquantitynumberPflichtunitstringunitPricenumberPflichttaxRatenumberPflichtgrossAmountnumberPflichtcurrencystringPflichtstatusstringPflichtWerte:
"open","cancelled","transferred"chargedAtstring (date-time)PflichtcancelledAtstring (date-time)posRefstringidempotentReplaybooleanduplicateWarningobjectAdvisory only: a potentially matching staff-entered item was found. The new charge has ALREADY been posted; reconcile in STRYK, do not resend.
Felder anzeigen (5)
chargeIdstring (uuid)descriptionstringgrossAmountnumberchargedAtstringposRefstring
[ { "chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "externalRef": "string", "bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "roomNumber": "string", "guestName": "string", "outletId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "outletName": "string", "description": "string", "quantity": 1.5, "unit": "string", "unitPrice": 1.5, "taxRate": 1.5, "grossAmount": 1.5, "currency": "string", "status": "open", "chargedAt": "2026-11-04T08:15:00.000Z", "cancelledAt": "2026-11-04T08:15:00.000Z", "posRef": "string", "idempotentReplay": false, "duplicateWarning": { "chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "description": "string", "grossAmount": 1.5, "chargedAt": "string", "posRef": "string" } } ]400Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }401Key could not be validated (missing, invalid, revoked, or verification unavailable). Check configuration and service status; do not automatically rotate credentials or replay under a new key.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }403Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }404Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }409Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }429100 requests per 60-second window per key, shared across application instances. No Retry-After header is currently returned. Wait at least 60 seconds, then retry with backoff and jitter. Reconcile uncertain writes before retrying.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }500Unexpected service error. A failed or lost response is not proof that a write was rolled back. Reconcile GET /charges/{externalRef} before retrying with the original key and request. Back off for transient 5xx and network failures. Escalate persistent errors with requestId; never change reference to bypass an error.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }
curl -X POST 'https://app.staystryk.com/api/v1/pos/public/charges/batch' \
-H "Authorization: Bearer $STRYK_POS_API_KEY" \
-H 'Content-Type: application/json' \
--data '[]'const response = await fetch('https://app.staystryk.com/api/v1/pos/public/charges/batch', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.STRYK_POS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify([]),
});
if (!response.ok) {
const problem = await response.json();
throw new Error(`${problem.code}: ${problem.detail} (request ${problem.requestId})`);
}
const data = await response.json();import os
import requests
response = requests.post(
"https://app.staystryk.com/api/v1/pos/public/charges/batch",
headers={
"Authorization": f"Bearer {os.environ['STRYK_POS_API_KEY']}",
},
json=[],
timeout=30,
)
response.raise_for_status()
data = response.json()[
{
"chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"externalRef": "string",
"bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"roomNumber": "string",
"guestName": "string",
"outletId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"outletName": "string",
"description": "string",
"quantity": 1.5,
"unit": "string",
"unitPrice": 1.5,
"taxRate": 1.5,
"grossAmount": 1.5,
"currency": "string",
"status": "open",
"chargedAt": "2026-11-04T08:15:00.000Z",
"cancelledAt": "2026-11-04T08:15:00.000Z",
"posRef": "string",
"idempotentReplay": false,
"duplicateWarning": {
"chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"description": "string",
"grossAmount": 1.5,
"chargedAt": "string",
"posRef": "string"
}
}
]GET/charges/{externalRef}Recover the durable state of one POS transaction
/charges/{externalRef}Recover the durable state of one POS transactionUse this read before retrying after a timeout or lost response. The externalRef is resolved only inside the authenticated API-key connection and returns open, cancelled, and transferred charges.
Scopes: Jeder gültige SchlüsseloperationId getChargeByExternalReference
Parameter, path
| Name | Ort | Typ | Beschreibung |
|---|---|---|---|
externalRefPflicht | path | string | - |
Antworten
200Current durable transaction state
application/jsonchargeIdstring (uuid)PflichtexternalRefstringPflichtbookingIdstring (uuid)PflichtroomNumberstringPflichtguestNamestringPflichtoutletIdstring (uuid)outletNamestringdescriptionstringPflichtquantitynumberPflichtunitstringunitPricenumberPflichttaxRatenumberPflichtgrossAmountnumberPflichtcurrencystringPflichtstatusstringPflichtWerte:
"open","cancelled","transferred"chargedAtstring (date-time)PflichtcancelledAtstring (date-time)posRefstringidempotentReplaybooleanduplicateWarningobjectAdvisory only: a potentially matching staff-entered item was found. The new charge has ALREADY been posted; reconcile in STRYK, do not resend.
Felder anzeigen (5)
chargeIdstring (uuid)descriptionstringgrossAmountnumberchargedAtstringposRefstring
{ "chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "externalRef": "string", "bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "roomNumber": "string", "guestName": "string", "outletId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "outletName": "string", "description": "string", "quantity": 1.5, "unit": "string", "unitPrice": 1.5, "taxRate": 1.5, "grossAmount": 1.5, "currency": "string", "status": "open", "chargedAt": "2026-11-04T08:15:00.000Z", "cancelledAt": "2026-11-04T08:15:00.000Z", "posRef": "string", "idempotentReplay": false, "duplicateWarning": { "chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "description": "string", "grossAmount": 1.5, "chargedAt": "string", "posRef": "string" } }400Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }401Key could not be validated (missing, invalid, revoked, or verification unavailable). Check configuration and service status; do not automatically rotate credentials or replay under a new key.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }404Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }429100 requests per 60-second window per key, shared across application instances. No Retry-After header is currently returned. Wait at least 60 seconds, then retry with backoff and jitter. Reconcile uncertain writes before retrying.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }500Unexpected service error. A failed or lost response is not proof that a write was rolled back. Reconcile GET /charges/{externalRef} before retrying with the original key and request. Back off for transient 5xx and network failures. Escalate persistent errors with requestId; never change reference to bypass an error.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }
curl 'https://app.staystryk.com/api/v1/pos/public/charges/externalRef' \
-H "Authorization: Bearer $STRYK_POS_API_KEY"const response = await fetch('https://app.staystryk.com/api/v1/pos/public/charges/externalRef', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.STRYK_POS_API_KEY}`,
},
});
if (!response.ok) {
const problem = await response.json();
throw new Error(`${problem.code}: ${problem.detail} (request ${problem.requestId})`);
}
const data = await response.json();import os
import requests
response = requests.get(
"https://app.staystryk.com/api/v1/pos/public/charges/externalRef",
headers={
"Authorization": f"Bearer {os.environ['STRYK_POS_API_KEY']}",
},
timeout=30,
)
response.raise_for_status()
data = response.json(){
"chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"externalRef": "string",
"bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"roomNumber": "string",
"guestName": "string",
"outletId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"outletName": "string",
"description": "string",
"quantity": 1.5,
"unit": "string",
"unitPrice": 1.5,
"taxRate": 1.5,
"grossAmount": 1.5,
"currency": "string",
"status": "open",
"chargedAt": "2026-11-04T08:15:00.000Z",
"cancelledAt": "2026-11-04T08:15:00.000Z",
"posRef": "string",
"idempotentReplay": false,
"duplicateWarning": {
"chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"description": "string",
"grossAmount": 1.5,
"chargedAt": "string",
"posRef": "string"
}
}DELETE/charges/{externalRef}Void an open charge owned by this POS connection
/charges/{externalRef}Void an open charge owned by this POS connectionOnly this key’s open items can be cancelled. Repeating a successful cancellation returns the existing cancelled item. Transferred/invoiced items return 409 pos_charge_already_invoiced and need the Finance correction workflow. Cancellation is not deletion or a refund.
Scopes: Jeder gültige SchlüsseloperationId cancelCharge
Parameter, path
| Name | Ort | Typ | Beschreibung |
|---|---|---|---|
externalRefPflicht | path | string | - |
Request-Body
reasonstring
Antworten
200Cancelled charge, or an idempotent repeat of the cancellation
application/jsonchargeIdstring (uuid)PflichtexternalRefstringPflichtbookingIdstring (uuid)PflichtroomNumberstringPflichtguestNamestringPflichtoutletIdstring (uuid)outletNamestringdescriptionstringPflichtquantitynumberPflichtunitstringunitPricenumberPflichttaxRatenumberPflichtgrossAmountnumberPflichtcurrencystringPflichtstatusstringPflichtWerte:
"open","cancelled","transferred"chargedAtstring (date-time)PflichtcancelledAtstring (date-time)posRefstringidempotentReplaybooleanduplicateWarningobjectAdvisory only: a potentially matching staff-entered item was found. The new charge has ALREADY been posted; reconcile in STRYK, do not resend.
Felder anzeigen (5)
chargeIdstring (uuid)descriptionstringgrossAmountnumberchargedAtstringposRefstring
{ "chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "externalRef": "string", "bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "roomNumber": "string", "guestName": "string", "outletId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "outletName": "string", "description": "string", "quantity": 1.5, "unit": "string", "unitPrice": 1.5, "taxRate": 1.5, "grossAmount": 1.5, "currency": "string", "status": "open", "chargedAt": "2026-11-04T08:15:00.000Z", "cancelledAt": "2026-11-04T08:15:00.000Z", "posRef": "string", "idempotentReplay": false, "duplicateWarning": { "chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f", "description": "string", "grossAmount": 1.5, "chargedAt": "string", "posRef": "string" } }400Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }401Key could not be validated (missing, invalid, revoked, or verification unavailable). Check configuration and service status; do not automatically rotate credentials or replay under a new key.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }404Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }409Request rejected
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }429100 requests per 60-second window per key, shared across application instances. No Retry-After header is currently returned. Wait at least 60 seconds, then retry with backoff and jitter. Reconcile uncertain writes before retrying.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }500Unexpected service error. A failed or lost response is not proof that a write was rolled back. Reconcile GET /charges/{externalRef} before retrying with the original key and request. Back off for transient 5xx and network failures. Escalate persistent errors with requestId; never change reference to bypass an error.
application/jsonerrorstringPflichtcodestringOptional machine-readable code. Do not parse localized error text. This list is extensible.
requestIdstringOptional diagnostic request identifier; retain for support without credentials or guest data.
{ "error": "string", "code": "pos_currency_mismatch", "requestId": "string" }
curl -X DELETE 'https://app.staystryk.com/api/v1/pos/public/charges/externalRef' \
-H "Authorization: Bearer $STRYK_POS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{
"reason": "string"
}'const response = await fetch('https://app.staystryk.com/api/v1/pos/public/charges/externalRef', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.STRYK_POS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
reason: 'string',
}),
});
if (!response.ok) {
const problem = await response.json();
throw new Error(`${problem.code}: ${problem.detail} (request ${problem.requestId})`);
}import os
import requests
response = requests.delete(
"https://app.staystryk.com/api/v1/pos/public/charges/externalRef",
headers={
"Authorization": f"Bearer {os.environ['STRYK_POS_API_KEY']}",
},
json={
"reason": "string",
},
timeout=30,
)
response.raise_for_status(){
"chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"externalRef": "string",
"bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"roomNumber": "string",
"guestName": "string",
"outletId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"outletName": "string",
"description": "string",
"quantity": 1.5,
"unit": "string",
"unitPrice": 1.5,
"taxRate": 1.5,
"grossAmount": 1.5,
"currency": "string",
"status": "open",
"chargedAt": "2026-11-04T08:15:00.000Z",
"cancelledAt": "2026-11-04T08:15:00.000Z",
"posRef": "string",
"idempotentReplay": false,
"duplicateWarning": {
"chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"description": "string",
"grossAmount": 1.5,
"chargedAt": "string",
"posRef": "string"
}
}Webhook-Ereignisse
Signaturprüfung und Wiederholungen
POSTchargeEventSTRYK sends a charge event to the configured HTTPS receiver
chargeEventSTRYK sends a charge event to the configured HTTPS receiverZustell-Header
| Name | Ort | Typ | Beschreibung |
|---|---|---|---|
X-STRYK-EventPflicht | header | string | - |
X-STRYK-Webhook-IdPflicht | header | string (uuid) | Subscription ID, not unique delivery ID. |
X-STRYK-Signature | header | string | Present only for subscriptions with a signing secret. Configure one and verify the original raw bytes. |
Payload
eventstringPflichtWerte:
"charge.posted","charge.cancelled","ping"hotelIdstringPflichttimestampstring (date-time)PflichtAttempt timestamp, may differ on retry.
dataobjectPflichtCharge events contain chargeId, externalRef if present, bookingId, roomNumber, guestName, description, grossAmount, currency, outletId/outletName if present. A ping carries test data instead.
Felder anzeigen (11)
chargeIdstring (uuid)externalRefstringbookingIdstring (uuid)roomNumberstringguestNamestringdescriptionstringgrossAmountnumbercurrencystringoutletIdstring (uuid)outletNamestringtestboolean
Antworten
- 200Durably accepted; any 2xx is accepted
- defaultDelivery failed; queued retry subject to attempt limit
{
"event": "charge.posted",
"hotelId": "string",
"timestamp": "2026-11-04T08:15:00.000Z",
"data": {
"chargeId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"externalRef": "string",
"bookingId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"roomNumber": "string",
"guestName": "string",
"description": "string",
"grossAmount": 1.5,
"currency": "string",
"outletId": "3f1c2b9a-6d4e-4b8a-9c7e-1a2b3c4d5e6f",
"outletName": "string",
"test": true
}
}