Web component

<svx-integration-catalog> is a custom element. It works in any framework, or none.


Loading it

<script type="module" src="https://embed.work.studio/v1.js"></script>

<svx-integration-catalog
  token="svx_st_…"
  tenant-id="your-tenant-id"
  scope-key="customer:acme"
></svx-integration-catalog>

The element renders a framed catalog and passes your credential to it over postMessage — the token never appears in a URL.


Attributes

Required

Attribute Description
token Short-lived session token (svx_st_…) minted by your server
tenant-id Your work.studio tenant id

Customer

Attribute Description
scope-key The customer this catalog acts for, e.g. customer:acme
env-id Environment id, when you run more than one

Appearance

Attribute Description
primary-color Accent colour for buttons and highlights
background-color Catalog background
text-color Body text colour
border-radius Corner radius, e.g. 8px
layout grid or list
title / subtitle Heading text above the catalog
show-title / show-search / show-categories Set to false to hide
visible-categories Comma-separated list of categories to show
notice A line of text above the tabs
hide-attribution true removes the work.studio attribution
height fixed turns off automatic resizing so you can size the element yourself

Content

Attribute Description
tabs Comma-separated: connections (the apps the customer connects), describe (the Automate tab: describe an automation, your templates, the customer's automations), automations (your ready-made Apps), assistant
default-tab Which tab opens first
connectors Comma-separated apps to offer, by name or connector id
templates Comma-separated automation template keys
integration-slug Open straight into one integration instead of the catalog

Methods

const el = document.querySelector('svx-integration-catalog');

el.connect('GitHub');              // open the connect dialog for one app
el.openConnection(connectorId);    // same, by connector id
el.openIntegration('slack-alerts');// open one integration's setup flow
el.showCatalog();                  // return to the full catalog
el.refresh();                      // reload catalog and connection status
el.setTheme({ primaryColor: '#111827' });

connect() accepts an app name or a connector id. If the app isn't one you offer, the element raises svx:connect:not-found rather than failing silently.


Events

Every event bubbles and carries a detail object.

Event detail
svx:catalog:loaded { count, categories, branding }
svx:catalog:error { error }
svx:integration:selected { id, globalId, name }
svx:activation:started { integrationId, integrationName }
svx:activation:completed { activationId, integrationGlobalId, status }
svx:wizard:open { globalId, slug, integrationId, integrationName }
svx:wizard:close { integration }
svx:oauth:required { url, connector }
svx:connect:open { connectorGlobalId, name }
svx:connect:close { connectorGlobalId }
svx:connect:not-found { connector }
svx:connection:completed { connectorGlobalId, name }
svx:connection:disconnected { connectorGlobalId, name }
svx:mcp:created { keyPrefix }
svx:mcp:revoked {}
svx:tab:changed { tab }
svx:automation:created { id, name, template?, changed?, recovered? }
svx:automation:run { id, runId }
svx:automation:deleted { id }
svx:assistant:message { conversationId }
svx:assistant:reply { conversationId }
svx:feedback:sent { surface, subjectId, rating, commented }

automation:created carries template when the customer added one of your templates and changed: true when they edited an existing automation. recovered: true means the connection dropped while the automation was being built, and the element found it in the customer's list afterwards.

Customer feedback

The customer can rate each automation the Automate tab builds, and each Assistant reply, with a thumbs up or down. After a thumbs-down they can say what went wrong. svx:feedback:sent fires for each rating: surface is AUTOMATION or ASSISTANT_REPLY, rating is 1 or -1, and commented says whether they wrote something. The comment text itself is not in the event.

The ratings are stored for you. Read them under What your customers said in Designer's Embed settings.

el.addEventListener('svx:connection:completed', (e) => {
  analytics.track('integration_connected', { app: e.detail.name });
});

Framework notes

import { useEffect, useRef } from 'react';

export function Catalog({ token, tenantId, scopeKey }) {
  const ref = useRef(null);

  useEffect(() => {
    const el = ref.current;
    const onConnected = (e) => console.log(e.detail);
    el.addEventListener('svx:connection:completed', onConnected);
    return () => el.removeEventListener('svx:connection:completed', onConnected);
  }, []);

  return (
    <svx-integration-catalog
      ref={ref}
      token={token}
      tenant-id={tenantId}
      scope-key={scopeKey}
    />
  );
}
vue
<template>
  <svx-integration-catalog
    :token="token"
    :tenant-id="tenantId"
    :scope-key="scopeKey"
    @svx:connection:completed="onConnected"
  />
</template>
<svx-integration-catalog id="catalog" token="…" tenant-id="…" scope-key="customer:acme">
</svx-integration-catalog>
<script>
  document.getElementById('catalog')
    .addEventListener('svx:connection:completed', (e) => console.log(e.detail));
</script>

In React, mark the tag as a custom element in your JSX types, or render it through a small wrapper as above.


Next steps

  • Authentication — minting tokens and setting the origin allowlist
  • SDK — building your own interface instead

Something not behaving as described? support@work.studio