Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/VisualGraphxLLC/API-HUB/llms.txt

Use this file to discover all available pages before exploring further.

A customer in API-HUB represents a single OnPrintShop storefront that you want to populate with supplier products. Each customer record holds the OAuth2 client credentials that API-HUB uses to authenticate with that storefront, product selections that define which catalog items belong on the storefront, and the markup rules that control pricing. Creating a customer is the first step before any product can be pushed.

Customer fields

The customers table stores all connection details for a storefront. Credentials are never stored in plain text — the ops_auth_config column uses the EncryptedJSON type decorator, which transparently encrypts and decrypts its contents using Fernet symmetric encryption (AES-128) derived from the SECRET_KEY environment variable.
A human-readable label for this storefront used throughout the admin UI. Must be unique enough to distinguish between storefronts (e.g., "Acme Promo – US" vs "Acme Promo – CA").
The root URL of the OnPrintShop instance — for example, https://store.example.com. All GraphQL mutations issued by n8n target paths relative to this URL.
The OAuth2 token endpoint where API-HUB exchanges client credentials for a bearer token — typically https://store.example.com/oauth/token.
The OAuth2 client identifier issued by the OPS admin panel. Stored in plain text because it is not a secret on its own.
Stored inside the encrypted JSONB column ops_auth_config as { "client_secret": "..." }. Never appears in API responses. Only vg_admin can set the initial secret; customer_admin may rotate it via PATCH /api/customers/{id} but cannot change URLs or other fields.
Boolean flag. When false, the markup engine rejects push requests for this customer with a 409 error, preventing accidental pushes to a decommissioned storefront.

Getting OPS credentials

Before creating a customer in API-HUB you need an OAuth2 client from the OnPrintShop admin panel.
1

Open the OPS admin panel

Log into your OnPrintShop instance as an administrator and navigate to Settings → API.
2

Create an OAuth client

Click Create OAuth client. Give it a descriptive name (e.g., api-hub-push), select the client_credentials grant type, and save. OPS will display the client ID and secret — copy both immediately, as the secret is shown only once.
3

Note the token endpoint

The token URL is shown on the API settings page. It is typically https://<your-store>/oauth/token.

Creating a customer

Navigate to Customers → New Customer in the API-HUB admin panel. Fill in all fields and paste the client secret from OPS. The secret is encrypted on the server before being written to the database — it is never stored or transmitted in plain text after this point.

Testing the connection

After creating a customer, verify that the credentials are valid before proceeding to product selection or push.
curl -X POST https://hub.example.com/api/customers/<customer_id>/test \
  -H "Authorization: Bearer <admin-token>"
A successful response:
{
  "ok": true,
  "customer_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "token_endpoint": "https://store.acmepromo.com/oauth/token"
}
If ok is false, the response includes http_status and error text from OPS. Common failures are an incorrect token URL, a revoked client secret, or a network timeout (the test request uses a 10-second timeout).
The test endpoint calls the live OPS token endpoint. Run it only when the storefront is reachable. A failed test does not deactivate the customer — you must fix the credentials and re-test manually.

Updating credentials

Role-based rules govern which fields can be updated via PATCH /api/customers/{customer_id}.

vg_admin

Can update any field: name, ops_base_url, ops_token_url, ops_client_id, is_active, and ops_client_secret.

customer_admin

Can only rotate ops_client_secret for their own customer. Attempting to modify any other field returns a 403 listing the rejected fields by name.
# Rotate the client secret (customer_admin or vg_admin)
curl -X PATCH https://hub.example.com/api/customers/<customer_id> \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"ops_client_secret": "new-s3cr3t"}'

Product selection and push status

Selecting products for a customer creates rows in customer_product_selections. Each row carries a status that tracks where the product is in the push lifecycle.

selected

The product has been chosen for this storefront but has not yet been pushed to OPS. It is in the push queue.

pushed

The product was successfully pushed to OPS. An ops_product_id exists in product_push_log for this customer–product pair.

stale

The underlying catalog record was updated after the last push. The product is in OPS but its data may be out of date. Re-push to sync.
Stale detection is automatic. When a supplier catalog sync updates a product that is already in pushed state for one or more customers, the system flips those customer_product_selections.status rows to "stale". The admin UI surfaces these as items requiring attention.

Per-product storefront configuration

Beyond markup rules (which apply to all products for a customer), you can configure per-product overrides via the product_storefront_configs table, managed through GET /api/ops-config/{customer_id}/product/{product_id} and POST /api/ops-config.
The OPS category ID to assign this product to on the storefront. Overrides the category detected from the product’s category field.
A JSONB object that can carry a fixed_unit_price (bypasses markup calculation entirely) or an extra_markup_pct layered on top of the customer’s markup rule. Supports nearest_99 and nearest_dollar rounding toggles.
A JSONB object mapping the hub’s master option IDs to the OPS-specific option IDs for this storefront. Used by the push pipeline to correctly wire product options in the setAdditionalOption mutation.
If no storefront config exists for a product, GET /api/ops-config/{customer_id}/product/{product_id} returns a blank config object with empty maps rather than a 404. This means the frontend can always render a config form without first checking for existence.

Deleting a customer

DELETE /api/customers/{customer_id} requires vg_admin. Deletion cascades to markup rules and push log entries for that customer. This is irreversible — you will need to recreate the customer and re-push all products if you delete by mistake.
Deleting a customer removes all push history for that storefront. If you need to rotate credentials or temporarily disable a storefront, use PATCH to set is_active: false instead.

Build docs developers (and LLMs) love