Developer API
The Kros plugin exposes services, an invoice provider, a webhook receiver, an order-edit UI component, and MCP tools for integration with yStore's invoicing system and external/automation clients.
Services
Access services via the plugin instance:
use Yui\Kros\Plugin;
$kros = Plugin::getInstance();
$api = $kros->getApi();
$invoices = $kros->getInvoices();
$webhooks = $kros->getWebhooks();
$dashboard = $kros->getDashboard();
$license = $kros->getLicense();
ApiService
Builds the authenticated Guzzle client used for every KROS OpenAPI call (getConnection()), sending the
saved API Token as a Bearer header against API Base URL. request(string $method, string $uri, array $options = []) wraps the call, adds Accept/Content-Type headers, and disables Guzzle's
http_errors so 4xx/5xx responses are still returned instead of throwing. Every response is passed through
validateMeta(), which reads the x-rate-limit-limit / x-rate-limit-remaining / x-rate-limit-reset
response headers (if present) and persists them onto the plugin's own settings (Rate Limit,
Remaining, Reset in the CP sidebar).
InvoiceService
Creates, updates, downloads, and lists KROS invoices from order data.
createInvoice(int $orderId, ?string $orderStatus, bool $manualCreate = false)-- creates an invoice for an order. When$manualCreateisfalse, it only proceeds if$orderStatusis one of the configured Generate invoice when statuses. Refuses to create a duplicate invoice for an order that already has one, refuses a zero-total order unless Zero Total Orders is enabled, and refuses an order whose increment ID is longer than 10 characters (KROS variable-symbol limit). Returnstrueon success,falseon an unexpected failure, or an array of human-readable error messages.createInvoiceFromData(array $invoiceData, bool $manualCreate = false)-- the invoice-provider entry point; builds the invoice from a normalized$invoiceDataarray (withorder_id/order_statusundermeta) instead of loading the order directly. Used byKrosInvoiceProvider::createInvoice().updateInvoice(int $orderId, ?string $orderStatus, bool $manualUpdate = false)-- re-sends the invoice data for an order that already has a recorded invoice.downloadInvoice(int $orderId)-- returns the invoice PDF as a CraftAsset, fetching it from KROS using the configured Invoice PDF Report ID if it hasn't been downloaded yet. Returnsfalseon failure.deleteInvoice(int $id)-- deletes a locally recorded invoice.syncRemoteInvoiceById(int $invoiceId)/deleteRemoteInvoiceById(int $invoiceId)-- used by the webhook receiver to keep the locally cached remote-invoice table (when Store Remote Invoices in Database is enabled) in sync with KROS-side changes.getInvoicesByOrderId(int $orderId)-- lists every invoice recorded for an order.getInvoiceByIncrementId(string $incrementId)-- looks up an invoice by the order's increment ID.getInvoices(int $page = 1, int $perPage = 10, ?string $searchTerm = null)-- paginated/searchable listing backing the Kros → Invoices CP page and itskros/invoices/get-listendpoint.
Every invoice/client/item detail sent to KROS is assembled from the order (address, line items, shipping, payment) and the plugin's settings (VAT payer type, tax class, invoice language, opening/closing text, due date, and whether shipping/payment are added as line items).
WebhookService
Manages the KROS-side webhook registration and validates incoming webhook signatures.
getResolvedWebhookUrl()-- returns the configured Webhook URL, or falls back to the plugin's ownkros/webhooks/receiveaction URL.syncWebhook()-- implements the create/update/delete logic for the KROS-side webhook (deletes it if Enable Webhooks is off and one was previously registered; otherwise creates or updates it with the configured URL, events, and secret, storing the returned webhook ID back onto the plugin settings). As of v1.3.0 this method is not called anywhere -- saving the settings form does not invoke it, so the webhook must currently be registered manually on the KROS side.validateSignature(string $payload, ?string $signature)-- computes an HMAC-SHA256 signature of the raw request body using Webhook Secret and compares it (constant-time) against the incoming Signature Header value (sha256=prefix stripped if present). Returnsfalse-- rejecting the request -- whenever the secret or the incoming signature is missing, so webhooks fail closed by default.
DashboardService
Extends the shared yui\craftcore\services\CoreDashboardService to build the Kros → Dashboard
modules: Total invoices, In this period, Synced to KROS, and Pending sync KPI tiles, and a
Recent invoices table (date, order, invoice ID, external ID; latest 12).
LicenseService
Backs the Kros → License CP page (shared yui/craft-core license activation/status UI).
Invoice provider
Yui\Kros\providers\KrosInvoiceProvider registers itself with handle kros on
yui\craft\services\sales\InvoiceService::EVENT_REGISTER_INVOICE_PROVIDERS, so it appears alongside any
other invoice provider yStore has registered.
public function isEnabled(): bool
{
return (bool)(Plugin::getInstance()?->getSettings()?->enabled ?? false);
}
The provider is enabled purely based on the Enabled settings toggle. createInvoice() delegates to
InvoiceService::createInvoiceFromData(), and getAttachments() returns the invoices already recorded for
the order (via $invoiceData['meta']['order_id']) using InvoiceService::getInvoicesByOrderId().
Webhooks
WebhooksController::actionReceive() (route: kros/webhooks/receive, anonymous access, CSRF validation
disabled since KROS posts without a Craft CSRF token) is the single entry point for KROS-originated events:
- If the plugin is disabled, the request is acknowledged (
{"ok": true}) without further processing. - The raw request body is checked against
WebhookService::validateSignature()using the header named by Signature Header (defaultX-Kros-Signature). A missing/invalid signature returns 401 and logs a warning with the request IP and header name -- it does not process the payload. - The JSON payload's event type (
event/type/eventType) and invoice ID (invoiceId/id/invoice.id) are extracted. If Store Remote Invoices in Database is enabled and an invoice ID is present, adeleted-type event callsdeleteRemoteInvoiceById(), any other event callssyncRemoteInvoiceById().
Configure the webhook via Settings → Kros → Webhooks (see Settings); a Webhook Secret
is mandatory for the endpoint to accept any request. As of v1.3.0, syncWebhook() is never invoked
automatically, so the webhook itself must be registered manually in KROS Fakturácia, pointed at
kros/webhooks/receive (or the configured Webhook URL) -- saving the settings form only stores the
local configuration used to validate and process the events KROS sends.
Order-edit component
When Show Kros Button is on, the plugin hooks into the order-edit-extra-actions template hook and
renders a Kros menu button on the order edit page
(kros/components/order/edit/manage-invoice.twig). The menu offers:
- Create Invoice -- shown when the order has no recorded invoice yet.
- Update Invoice -- shown when the order already has one.
- Download Invoice -- always available.
These map to InvoiceController::actionCreate(), actionUpdate(), and actionDownload().
MCP Tools
When the yui/craft-mcp plugin is installed, Kros registers three MCP tools on
yui\mcp\Plugin::EVENT_REGISTER_TOOLS, all extending the shared AbstractKrosTool base, which accepts an
order identifier (order_id and/or increment_id).
kros_get_invoices
Lists all Kros invoices for a given order.
Output:
{
"order_id": 123,
"count": 1,
"invoices": ["..."]
}
kros_create_invoice
Manually creates a Kros invoice for an order, bypassing the order-status trigger and forcing creation. Fails if an invoice already exists for the order. Requires WRITE permission.
kros_download_invoice
Downloads (or returns the already-cached asset for) the Kros invoice PDF for an order. Returns the asset
URL and filename, or success: false with an error message if the PDF could not be fetched.
{
"success": true,
"order_id": 123,
"url": "https://.../invoice.pdf",
"filename": "invoice.pdf"
}
Requires WRITE permission.
Settings model
Yui\Kros\models\Settings (extends yui\craftcore\models\BasePluginSettingsModel) holds every field
documented in Settings. Validation: apiBaseUrl, apiToken, dueDateDays,
createInvoiceOnOrderStatus, and invoiceReportId are required whenever the plugin is enabled
(Settings::rules()). apiToken, apiBaseUrl, and numberingSequence are site-overridable
(siteOverridableAttributes()), so a multi-site store can use different KROS credentials/sequences per
site.
CP Routes
| Route | Purpose |
|---|---|
kros / kros/dashboard | Dashboard |
kros/invoices, kros/invoices/get-list, kros/invoices/delete | Invoice list, AJAX listing, delete |
kros/invoice/create/<orderId>, /update/<orderId>, /download/<orderId> | Manual invoice actions from the order edit page |
kros/settings | Settings |
kros/webhooks/receive | Webhook receiver (anonymous, KROS-originated) |
kros/license | License activation/status |
kros/license/redeem, /revoke, /activate, /delete, /copy-token | License actions |
Permissions
The plugin registers three CP user permissions under the Kros heading: yui:kros:create (Create
invoice), yui:kros:update (Update invoice), and yui:kros:download (Download invoice).
Compatibility
- Craft CMS 5+
- Craft Commerce and
yui/craft-core^1 - KROS Economy API (
https://api-economy.kros.sk) -- see KROS API docs and invoice reference - Optional:
yui/craft-mcp, for the MCP tools described above