Automations
Run tools from workflows and background jobs — stateless execution with the same credentials, policies, and traces as your agents — and react to platform events.
Scenario: Not everything happens inside a conversation. Before a support chat starts, Acme enriches the customer from HubSpot. After a call ends, a summary email goes out and the CRM gets updated — from a queue worker, minutes later. Same tools, same per-user credentials, no agent in the loop.
Stateless execution
actions.execute runs one action by slug — no session, no conversation:
const result = await protobox.actions.execute('HUBSPOT_SEARCHCONTACTS', {
actorId: 'user_123', // whose credential to use
arguments: { query: 'initech.com' },
});
if (result.status === 'completed') {
console.log(result.data);
} else if (result.status === 'pending_approval') {
// a toolset policy gated it — see Human-in-the-loop
} else {
console.error(result.error?.code, result.error?.message); // e.g. 'not_connected'
}Every execute lands in the same execution log as agent calls — one audit trail for the whole product.
Find the action and its schema
const actions = await protobox.actions.search({ connectorSlug: 'hubspot', query: 'contact' });
const schema = await protobox.actions.getSchema('HUBSPOT_SEARCHCONTACTS');
// schema.inputSchema — validate your job payloads against it in CIDry-run from CI
dryRun: true validates arguments and resolves the credential without calling the provider — perfect for smoke-testing a workflow deploy:
const check = await protobox.actions.execute('ACME_CREATETICKET', {
actorId: 'user_123',
arguments: { subject: 'smoke' },
dryRun: true,
});Relay your own context
context.forward is carried verbatim as an X-Protobox-Context header to connectors that opted in (forwardContext: true at registration) — so your API can correlate tool calls to your conversations without Protobox parsing anything:
await protobox.actions.execute('ACME_CREATETICKET', {
actorId: 'user_123',
arguments: { subject: 'Renewal follow-up' },
context: { forward: JSON.stringify({ conversationId: 'c_991' }) },
});The three moments
| Moment | Pattern |
|---|---|
| Before an interaction | Enrich at boot: a few read-only actions.execute calls, results into your prompt/context |
| During | The agent path — sessions or adapters |
| After | Queue worker: write-backs, follow-up email, ticket updates — gated by approvals where they're risky |
Reacting to events
Today, the platform pushes its own events to your webhook — connection lifecycle and execution outcomes (reference). The high-leverage automation pair:
switch (event.type) {
case 'connection.activated':
// kick off a first-sync job for this user's newly connected app
await enqueueFirstSync(event.data.callerId, event.data.integrationId);
break;
case 'execution.failed':
// alert on failures from unattended jobs
await notifyOncall(event.data.executionId);
break;
}On the roadmap: provider-event triggers ("new email arrived", "deal stage changed" → call your endpoint). The protobox.triggers namespace is reserved and throws NotImplementedError until delivery ships. Until then, poll read actions on a schedule for provider-side changes.
Production notes
- Retries are yours. The SDK makes exactly one attempt per call — no built-in retry or backoff. Run executes from a queue with your retry policy; on
rate_limitederrors, honorerror.retryAfter. - Idempotency:
idempotencyKeyis accepted onexecutebut not enforced yet (it arrives with a later phase). Until then, make write actions safe to repeat at your layer — dedupe by your job id before enqueueing. - Multi-account actors: pass
accountKeyalongsideactorIdto pick which of the user's accounts the job runs as.
Related
- Your API as agent tools — the actions your jobs will call most
- Human-in-the-loop — approvals pause background writes too