Skip to main content
Apps consume services through auto-generated clients. Each tool defined in the service becomes a typed method on the client, and the framework handles credential resolution transparently.

Generate a service client

synthetiq service client <service-name>
This generates a typed client package (@synthetiq/services-<name>-client) that you can import in your app’s backend code.

Call a service from a backend procedure

// src/server/routes/channels.ts
import SlackClient from '@synthetiq/services-slack-client';
import { router, scopedProcedure } from '@synthetiq/app-framework/server';

export const channelsRouter = router({
  listChannels: scopedProcedure([])
    .meta({ description: 'List Slack channels' })
    .query(async () => {
      const client = new SlackClient();
      return await client.listChannels({ limit: 100 });
    }),
});
The client resolves the authenticated user’s credentials at call time — no API keys or tokens appear in app code. Service clients can only be used in backend code (src/server/).

Streaming calls

For services that support streaming (e.g., LLM providers), use the callback variant:
const client = new AnthropicClient();

let response = '';
await client.streamMessageWithCallback(
  {
    model: 'claude-sonnet-4-20250514',
    messages: [{ role: 'user', content: 'Hello' }],
    max_tokens: 1024,
  },
  (chunk) => { response += chunk; },
  () => { console.log('Complete:', response); },
  (error) => { console.error('Error:', error); },
);