ByteChef Embedded, Part 2: The ComponentKit Playground

On this page
TL;DR: Not everything needs a workflow. The ComponentKit lets your app call any connector action directly on a connected user's account:
POST /api/embedded/v1/{externalUserId}/components/{component}/versions/{version}/actions/{action}with an{ input }body runs, say,slack/sendChannelMessageoropenai/askwith the user's stored credentials and returns the result. The embedded sample app's ComponentKit Playground is a form over that one endpoint. This is part two of the series.
In part one your users connected their apps. An embedded platform is more than a workflow engine, though. It is also a pre-authenticated API client for 280+ services, and sometimes you want that directly. Your app needs to post one Slack message, enrich one contact, or run one OpenAI completion, as your customer, without authoring or running a workflow for it. That's the ComponentKit.
The Playground Page
The page is a form with four fields and a result panel. Pick a component, a version, an action, and a JSON input, and it posts them to the app's own API route:
export default function ComponentKitPage() {
const [componentName, setComponentName] = useState("openai");
const [componentVersion, setComponentVersion] = useState(1);
const [actionName, setActionName] = useState("ask");
const [inputJson, setInputJson] = useState(JSON.stringify(input, null, 2));
const [result, setResult] = useState<string | null>(null);
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
const response = await fetch("/api/component-kit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ actionName, componentName, componentVersion, input: JSON.parse(inputJson) }),
});
setResult(JSON.stringify(await response.json(), null, 2));
};
// ...a Card with the four inputs, and a Card that renders `result` in a <pre>
}The defaults are openai / version 1 / ask, and the input textarea is pre-filled with a chat request:
{
"model": "gpt-4o",
"format": "ADVANCED",
"messages": [{ "role": "USER", "content": "Say hello" }],
"response": { "responseFormat": "TEXT" }
}Click Execute Action and the response lands in the right-hand card, as JSON. Errors from ByteChef land there too, so a wrong action name or a missing required input shows you exactly what the server complained about.
The Route: One POST to ByteChef
The route adds the connected user's JWT and forwards the call to the ComponentKit endpoint:
const response = await fetch(
`${BYTECHEF_APP_BASE_URL}/api/embedded/v1/${BYTECHEF_EXTERNAL_USER_ID}/components/${componentName}/versions/${componentVersion}/actions/${actionName}`,
{
method: "POST",
headers: { Authorization: `Bearer ${jwtToken}`, "Content-Type": "application/json", "X-Environment": BYTECHEF_ENVIRONMENT },
body: JSON.stringify({ input }),
}
);ByteChef finds the integration this user connected for that component, takes the connection behind it, and runs the action with those credentials. The response comes back as-is. No workflow, no trigger, no execution history, just a synchronous "do this thing in their account."
The shape is universal. Swap in slack / sendChannelMessage, googleSheets / insertRow, or hubspot / createContact and nothing else changes. The action's input schema is the same one the workflow editor uses, so if you know what a field looks like in a workflow, you know what to put in input.
If a user has connected the same app more than once, pass the X-Instance-Id header to say which integration instance you mean. Without it, ByteChef picks the user's instance for that component.
Why This Matters
The ComponentKit turns ByteChef Embedded from "a workflow feature" into "an integration layer for your whole product." Anywhere in your app where you'd otherwise hand-roll an API client, with OAuth, token refresh, request signing, and response parsing, times 280 services, you make one call instead:
- In-product actions. A "Send to Slack" button that just works, on the user's connection.
- AI tool calls. Give an LLM the ability to act in the user's apps, which is exactly what part three builds.
- Backend glue. Server-side enrichment, sync, or notification without standing up a workflow.
Because it rides the same connection and JWT as everything else in this series, it's automatically scoped, authenticated, and refreshed. You send one POST; ByteChef is the API client you didn't write.
What You Didn't Build
For one POST:
- A typed action invocation across 280+ connectors.
- Credential resolution and refresh, per connected user, per environment.
- The auth handshake and request for whichever provider you named.
- A uniform response shape instead of hundreds of bespoke API clients.
Running It Yourself
On top of the setup from part one:
- Connect the integration you want to call. The playground defaults to OpenAI, so connect an OpenAI integration for your demo user through the connect dialog first. The API key lives in that connection, not in the sample app's
.env.local. - Try another app. Connect Slack, change the form to
slack/1/sendChannelMessage, and give it achannelandtext. Same page, same route, different account.
What's Next
The ComponentKit is your app calling one action at a time. Hand those same actions to a model and it can pick which one to call, fill in the input, and read the result. That's part three: the ComponentKit Chat.
Following along? Connect an integration, open the ComponentKit Playground, and execute one action on a connected account. It's the simplest possible embedded integration.
Subscribe to the ByteChef Newsletter
Get the latest guides on complex automation, AI agents, and visual workflow best practices delivered to your inbox.