--- title: Creating the client description: "Each integration has a client that performs the actual HTTP requests. Usually this is a wrapper around an official SDK provided by the service." --- ### `src/index.ts` This is where the client should live. We're adopting the naming convention of naming the class after the service, without a suffix or prefix. We prefer the exported name be `Slack` instead of something like `SlackIntegration` or `SlackConnector` ## Example: GitHub Comments are for instructional purposes only and should be removed in your implementation. ```ts import { ConnectionAuth, IO, TriggerIntegration } from "@trigger.dev/sdk"; //the official GitHub SDK import { Octokit } from "octokit"; //define the options that will be passed to the constructor export type GithubIntegrationOptions = { //this is required id: string; //GitHub can use OAuth or Personal Access Tokens, so this is optional token?: string; }; export class Github implements TriggerIntegration { private _options: GithubIntegrationOptions; private _client?: Octokit; private _io?: IO; private _connectionKey?: string; constructor(private options: GithubIntegrationOptions) { //if the token key is present but undefined, throw an error //this is NOT the same as just: if (!options.token) //it's a common user bug where an env var is used for the token but hasn't been set if (Object.keys(options).includes("token") && !options.token) { throw `Can't create GitHub integration (${options.id}) as token was undefined`; } this._options = options; } //this is used internally to identify the integration get id() { return this.options.id; } //this is used internally to identify the integration, and display nicely in the dashboard get metadata() { return { name: "GitHub", id: "github" }; } //the two possible options are "LOCAL" or "HOSTED" //LOCAL means that the client is using local auth (like a token) //HOSTED means that the client is using hosted auth (like OAuth) //GitHub supports both, and we use the presence of the token to determine which one to use get authSource() { return this._options.token ? ("LOCAL" as const) : ("HOSTED" as const); } //before the `run()` method is called on a Job, this function gets invoked //this is important because the authentication data is dynamic, and can change (like OAuth credentials refreshing) cloneForRun(io: IO, connectionKey: string, auth?: ConnectionAuth) { const github = new Github(this._options); github._io = io; github._connectionKey = connectionKey; if (this._options.token) { github._client = new Octokit({ auth: this._options.token, retry: { enabled: false, }, }); } else { if (!auth) { throw new Error("No auth"); } github._client = new Octokit({ auth: auth.accessToken, retry: { enabled: false, }, }); } return github; } } ``` The `TriggerIntegration` interface requires three properties and one method to be implemented: The `id` that uniquely identifies the Integration. This should always be passed through the constructor options. A unique identifier for the Integration. For example, the OpenAI Integration has an id of `"openai"`. The name of the Integration. For example, the OpenAI Integration has a name of `"OpenAI"`. "LOCAL" should be returned for API keys. "HOSTED" should be returned for OAuth. This method is called before the `run()` method is called on a Job. This is important because the authentication data is dynamic, and can change (like OAuth credentials refreshing). This method should return a new instance of the Integration, with the new authentication data, io, and connectionKey set so they can be used by runTask and any Triggers.