StoreOSv0.15.0
Plugins

Plugin API

Console-side GraphQL for installing, configuring, validating, and uninstalling StoreOS plugins.

Where these operations live

Plugin operations are on core-api, the console API — not the storefront API.

Endpointhttps://core-api.storeos.dev/graphql
AuthAuthenticated merchant session
Tenantx-tenant: <tenant-uid> header

Every operation is scoped to the tenant in that header. There is no cross-tenant plugin call.

Storefront apps do not use this API. If you are building a storefront and need the GA4 ID or a chat widget's app ID, read Reading plugins from your storefront instead.


Configure a plugin

plugin__configure writes credentials for one plugin. The input is a discriminated bag: set pluginId, then fill the one field matching that plugin.

mutation ConfigureSteadfast($input: ConfigurePluginInput!) {
  plugin__configure(input: $input)
}
{
  "input": {
    "pluginId": "steadfast",
    "steadfast": {
      "api_key": "…",
      "secret_key": "…",
      "webhook_token": "…"
    }
  }
}

Returns Boolean. Behavior worth knowing:

  • The write is a $set on that plugin's path only. Configuring Pathao cannot touch Steadfast, and a partial payload cannot wipe a sibling plugin.
  • pluginId must be one of the 20 INSTALLABLE_PLUGIN_IDS. Anything else is rejected by validation before reaching the service.
  • Per-plugin format rules run server-side. A value that fails its pattern is reported as a missing configuration payload, not stored. The exact patterns are in the catalog reference.
  • google-analytics and google-tag-manager are rejected with "Use the Google OAuth plugin mutations for this integration".

The input field name is not always the plugin ID — it is camel-cased:

pluginIdInput field
steadfaststeadfast
pathaopathao
bkashbkash
sslcommerzsslcommerz
walandwaland
bulksmsbdbulksmsbd
smtpsmtp
google-search-consolegoogleSearchConsole
popupsmartpopupsmart
hotjarhotjar
meta-pixelmetaPixel
microsoft-claritymicrosoftClarity
lucky-orangeluckyOrange
sharechat-pixelshareChatPixel
facebook-domain-verificationfacebookDomainVerification
intercomintercom
tawk-totawkTo
whatsapp-chatwhatsappChat

Payments take a mode

{
  "input": {
    "pluginId": "bkash",
    "bkash": {
      "sandbox": { "appKey": "…", "appSecret": "…", "username": "…", "password": "…", "secretKey": "…" },
      "live":    { "appKey": "…", "appSecret": "…", "username": "…", "password": "…", "secretKey": "…" },
      "activeMode": "sandbox"
    }
  }
}

Flipping a store live is a re-configure with activeMode: "live" — the sandbox set stays where it is.


Uninstall a plugin

mutation Uninstall($input: UninstallPluginInput!) {
  plugin__uninstall(input: $input)
}
{ "input": { "pluginId": "hotjar" } }

$unsets that one path. The credentials are gone — this is not a soft disable, and there is no undo. Re-enabling means configuring again.


Validate a courier

Checks the stored credentials against the courier's API. Use it right after configuring, so the merchant learns about a bad key immediately rather than on their first real parcel.

mutation Validate($input: ValidateCourierInput!) {
  plugin__validateCourier(input: $input)
}
{ "input": { "provider": "pathao" } }

provider is pathao or steadfast. Returns true, or throws BadRequestException carrying the provider's own error message.


Check payment configuration

query PaymentStatus($provider: PaymentProviderName!) {
  plugin__paymentProviderConfigurationStatus(provider: $provider) {
    provider
    configured
    missingFields
  }
}

provider is bkash or sslcommerz. missingFields lists required keys that are empty on the active credential set — so a store in sandbox mode is judged on its sandbox keys. When no credentials exist at all, every required field is returned.


Send a test notification

mutation TestNotification($input: TestNotificationInput!) {
  plugin__testNotificationDeliveries(input: $input) {
    channel
    provider
    recipient
    recipientName
    configured
    idempotencyKey
    status
  }
}
{
  "input": {
    "channel": "SMS",
    "recipientName": "Test User",
    "recipientPhoneNumber": "+8801711000000",
    "message": "Test from StoreOS"
  }
}

channel is WHATSAPP, SMS, or EMAIL — resolved to the configured provider for that channel (waland, bulksmsbd, smtp). configured tells you whether credentials were present; idempotencyKey identifies the queued delivery.


Webhook URLs

query WebhookUrls {
  plugin__webhookUrls {
    provider
    kind
    url
  }
}

Returns the four public endpoints for this tenant. kind is webhook or callback. Full detail in Webhooks & callbacks.


Google OAuth plugins

Google Analytics, Google Tag Manager, and Google Search Console connect through OAuth. The merchant grants access once, then picks a container or property from their own account — no IDs are typed by hand, and StoreOS holds the tokens, never your storefront.

1 — Check connection

query GoogleStatus {
  plugin__googleOAuthStatus { oauthConfigured connected email }
}

oauthConfigured is about the platform (are Google credentials set up at all); connected is about this tenant.

2 — Start the flow

query AuthorizeUrl($input: GoogleOAuthAuthorizeInput!) {
  plugin__googleOAuthAuthorizeUrl(input: $input) { url }
}

purpose is gtm, ga, or gsc. returnPath is where the merchant lands afterwards. Redirect the browser to url.

3 — List and select

PurposeListSelectCreate
GTMplugin__googleGtmAccounts, plugin__googleGtmContainersplugin__selectGtmContainerplugin__createGtmContainer
GA4plugin__googleGaAccounts, plugin__googleGaMeasurementIdsplugin__selectGaMeasurementplugin__createGaMeasurement, plugin__provisionGaAccount
Search Console—plugin__selectSearchConsoleMetaplugin__verifyGoogleSearchConsole

Selecting is what actually writes plugins.analytics.gtm / plugins.analytics.ga — the OAuth grant alone changes nothing on the storefront.

4 — Disconnect

MutationEffect
plugin__clearGtmContainerDrops the selected GTM container
plugin__clearGaMeasurementDrops the selected GA4 measurement
plugin__clearSearchConsoleDrops the Search Console verification
plugin__disconnectGoogleOAuthRevokes the whole Google connection for the tenant

Merchants who only want to stop one tag should use the specific clear… mutation — plugin__disconnectGoogleOAuth drops everything Google at once.

On this page