OpenShopy
Przewodnik

Core concepts

Stores and multi-tenancy

Every record (product, order, customer, invoice, …) belongs to exactly one store. API keys are issued per store, so a key can only ever see and change its own store's data. A person can be a member of many stores with a different role in each.

Roles and permissions

CapabilityViewerStaffAdminOwner
See dashboard, orders, products, customers, reports✓✓✓✓
Create and edit products, orders, customers, discounts✓✓✓
Confirm payments, ship orders, issue invoices and refunds✓✓✓
Import data, send notifications and campaigns✓✓✓
Store settings, taxes, shipping, automations✓✓
API keys, team invites, activity log✓✓
Remove the store owner, transfer ownership✓

Permissions are enforced by the database itself (row-level security), not only by the interface.

Money

All amounts are integers in minor units (grosze / cents) together with a currency code.

ValueMeaning
{"price": 12999, "currency": "PLN"}129.99 PLN
{"total": 500, "currency": "EUR"}5.00 EUR

Never send floats such as 129.99. Supported currencies: PLN, EUR, USD.

Exchange rates

Each store has a base currency and an exchange_rates table expressed as units of currency per 1 unit of base currency. Carts can be created in any supported currency; prices are converted from the base currency and rounded to whole minor units. The dashboard can display all totals in a different currency using the same rates.

Languages

Customer-facing content (notifications, payment page, invoices) is available in Polish (pl) and English (en). The order's language decides which template is used.

Order lifecycle

An order has three independent status fields:

FieldValues
statusopen, processing, completed, cancelled
payment_statusunpaid, awaiting_confirmation, paid, partially_refunded, refunded
fulfillment_statusunfulfilled, partial, fulfilled, returned
text
checkout ──► open / unpaid
              │ customer clicks "I have paid"
              ▼
         open / awaiting_confirmation ──► alert for the team
              │ staff confirms the transfer
              ▼
      processing / paid ──► "payment received" notification, optional automatic invoice
              │ shipment created with tracking number
              ▼
   processing / fulfillment: partial or fulfilled ──► "order shipped" notification
              │ all shipments delivered
              ▼
          completed

Orders have a sequential, human-readable name (for example #1001, prefix configurable) and a secret payment_token used for the public payment page.

Sources: checkout (created through cart checkout), api (created directly through the API), manual (created in the dashboard or imported).

Products and variants

A product has a title, slug, rich-text description, status (draft, active, archived), vendor, type, tags, tax class, SEO fields, up to three options (for example Size, Color) and one or more variants. Each variant has its own price, compare-at price, cost, SKU, barcode, weight, stock and inventory settings. Images belong to the product and can optionally be linked to a variant.

Inventory

Stock is tracked per variant when track_inventory is true. Every change — sale, cancellation, return, manual adjustment, import — is written to the inventory movement log with the actor, reason and resulting stock. When stock crosses the low-stock threshold an inventory.low_stock event fires.

Audit trail

Sensitive changes are recorded automatically: price and product changes, payment confirmations, cancellations, refunds, stock adjustments, team and settings changes, API key creation and revocation. Each entry stores who did it (team member or API key), when, and the before/after values. See Activity in the dashboard.

Rate limits

Each API key has a per-minute request limit (default 120, configurable from 10 to 5000). Responses include X-RateLimit-Limit and X-RateLimit-Remaining. When exceeded, the API returns 429 with Retry-After: 60.