|
1 | 1 | # Klaviyo Typescript SDK |
2 | 2 |
|
3 | | -- SDK version: 7.0.0 |
| 3 | +- SDK version: 7.0.0-beta.1 |
4 | 4 |
|
5 | 5 | - Revision: 2023-10-15 |
6 | 6 |
|
@@ -47,7 +47,7 @@ This SDK is organized into the following resources: |
47 | 47 |
|
48 | 48 | You can install this library using `npm`. |
49 | 49 |
|
50 | | - |
| 50 | +`npm install [email protected]-beta.1` |
51 | 51 |
|
52 | 52 |
|
53 | 53 | ## source code |
@@ -206,6 +206,170 @@ Profiles.getProfiles().then(result => { |
206 | 206 | }); |
207 | 207 | ``` |
208 | 208 |
|
| 209 | +## Using OAuth to connect to multiple Klaviyo accounts. |
| 210 | + |
| 211 | +For users creating integrations or managing multiple Klaviyo accounts, Klaviyo's OAuth authentication will make these tasks easier. |
| 212 | + |
| 213 | +### Getting started with OAuth |
| 214 | + |
| 215 | +First, configure an integration. If you haven't set up an integration, learn about it in this [guide](https://help.klaviyo.com/hc/en-us/articles/18819413031067#h_01HACEKGF2DBDMGJ4JG6TV4AMN) |
| 216 | + |
| 217 | +### Making API Calls with OAuth |
| 218 | +The `klaviyo-api` package can keep your `access token` up to date. If you have already developed a system for refreshing tokens or would like a more minimalist option, skip to [OAuthBasicSession](#oauthbasicsession) |
| 219 | + |
| 220 | +#### TokenStorage |
| 221 | +For the OAuthApi to be storage agnostic, this interface must be implemented for the `OAuthApi` to retrieve and save you `access` and `refresh` tokens. |
| 222 | +Implement the `retrieve` and `save` functions outlined in the interface. If you need help getting started, check out the `storageHelpers.ts` in the [Klaviyo Example Typescript Integration](https://github.com/klaviyo-labs/node-integration-example) |
| 223 | + |
| 224 | +Your implementation needs to include two methods: |
| 225 | +1. `save` is called after creating a new `access token` via the authorization flow or after refreshing the `access token`. |
| 226 | + Your code needs to update (and insert if you are going to be using `createTokens()`) the new `access` or `refresh` token information into storage |
| 227 | + to keep track of which of your integration users' access information you are referencing, the `customerIdentifer` is a unique value to help with lookup later. |
| 228 | + ```typescript |
| 229 | + save(customerIdentifier: string, tokens: CreatedTokens): Promise<void> | void |
| 230 | + ``` |
| 231 | +2. `retrieve` leverages the `customerIdentifier` to look up the saved token information and returns it for the `OAuthApi` to use |
| 232 | + ```typescript |
| 233 | + retrieve(customerIdentifier: string): Promise<RetrievedTokens> | RetrievedTokens |
| 234 | + ``` |
| 235 | + |
| 236 | +```typescript |
| 237 | +import { TokenStorage } from 'klaviyo-api'; |
| 238 | +class <Your Token Storage Class Name Here> implements TokenStorage |
| 239 | +``` |
| 240 | +
|
| 241 | +#### OAuthApi |
| 242 | +This class holds the information about your specific integration. It takes three inputs: |
| 243 | +1. `clientId` - This is the id of your integration. Retrieve it from your integration's settings page |
| 244 | +2. `clientSecret` - This is the secret for your integration. The secret is generated upon the creation of your integration. |
| 245 | +3. `tokenStorage` - This is an instance of your implementation of `TokenStorage` and is called automatically when creating and refreshing `access tokens` |
| 246 | +
|
| 247 | +
|
| 248 | +```typescript |
| 249 | +import { OAuthApi } from 'klaviyo-api'; |
| 250 | + |
| 251 | +const oauthApi = new OAuthApi("<client id>", "<client secret>", <instance of your TokenStorage implimentation>) |
| 252 | +``` |
| 253 | + |
| 254 | +#### `OAuthSession` |
| 255 | +To make an API call, you need to create an `OAuthSession` instance. This session object is the OAuth equivalent of `ApiKeySession` and is used similarly. |
| 256 | + |
| 257 | +It takes two properties |
| 258 | +1. `customerIdentifier` - This is how the session is going to grab a user's authentication information and let your implementation of `TokenStorage` know where to save any update `access token` |
| 259 | +2. `oauthApi` - This is the instance of `OAuthApi` created above. It will dictate how the session `saves` and `retrieves` the `access tokens` |
| 260 | +3. `retryOptions` - OPTIONAL - the `RetryOptions` instance outlines your desired exponential backoff retry options, outlined in [Retry Options](#retry-options) above |
| 261 | + |
| 262 | +```typescript |
| 263 | +import { OAuthSession, ProfilesApi } from 'klaviyo-api'; |
| 264 | + |
| 265 | +const session = new OAuthSession(customerIdentifier, oauthApi) |
| 266 | + |
| 267 | +//Pass the session into the API you want to use |
| 268 | +const profileApi = new ProfilesApi(session) |
| 269 | +``` |
| 270 | + |
| 271 | +#### `OAuthBasicSession` |
| 272 | +If you don't want to deal with any of the helpers above or don't want `klaviyo-api` to refresh your tokens for you, this is the alternative. |
| 273 | + |
| 274 | +The `OAuthBasicSession` takes up to two parameters |
| 275 | +1. `accessToken` - The token is used in the API calls' authentication |
| 276 | +2. `retryOptions` - OPTIONAL - the `RetryOptions` instance outlines your desired exponential backoff retry options, outlined in [Retry Options](#retry-options) above |
| 277 | + |
| 278 | +```typescript |
| 279 | +import { OAuthBasicSession } from 'klaviyo-api'; |
| 280 | + |
| 281 | +const session = new OAuthBasicSession("<access token>") |
| 282 | + |
| 283 | +//Pass the session into the API you want to use |
| 284 | +const profileApi = new ProfilesApi(session) |
| 285 | +``` |
| 286 | + |
| 287 | +Remember to check for `401` errors. A 401 means that your token is probably expired. |
| 288 | + |
| 289 | +#### `KlaviyoTokenError` |
| 290 | + |
| 291 | +If an error occurred during an API call, check the error type with `isKlaviyoTokenError`. The name property will reflect which step the error occurred, reflecting whether it happened during creating, refreshing, saving, or retrieving the `name` tokens. The `cause` property will hold the error object of whatever specific error occurred. |
| 292 | + |
| 293 | +### Authorization Flow |
| 294 | + |
| 295 | +Build The authorization flow in the same application as with the rest of your integrations business logic or separately. |
| 296 | +There is no requirement that the authorization flow has to be backend and can be implemented entirely in a frontend application (in that case, you can ignore this section, as this repo shouldn't use this for frontend code) |
| 297 | + |
| 298 | +To understand the authorization flow, there are two major resources to help: |
| 299 | +1. [OAuth authorization guide](https://help.klaviyo.com/hc/en-us/articles/18819413031067) |
| 300 | +2. [Node Integration Example](https://github.com/klaviyo-labs/node-integration-example) |
| 301 | + |
| 302 | +If you implement your authorization flow on a node server, you can use these exposed helper functions. |
| 303 | + |
| 304 | +#### OAuthApi |
| 305 | + |
| 306 | +The OAuthApi class also exposes helpful Authorization flow utilities. |
| 307 | + |
| 308 | +1. `generateAuthorizeUrl` - This helps correctly format the Klaviyo `/oauth/authorize` URL the application needs to redirect to so a user can approve your integration. |
| 309 | + 1. `state` - This is the only way to identify which user just authorized your application (or failed to). `state` is passed back via query parameter to your `redirectUrl`. |
| 310 | + 2. `scope` - The permissions the created `access tokens` will have. The user will be displayed these scopes during the authorization flow. For these permissions to work, also add them to your app settings in Klaviyo [here](www.klaviyo.com/oauth/client) |
| 311 | + 3. `codeChallenge` - This is the value generated above by the `generateCode` function. |
| 312 | + 4. `redirectUrl` - This is the URL that Klaviyo will redirect the user to once Authorization is completed (even if it is denied or has an error). |
| 313 | + Remember to whitelist this redirect URL in your integration's settings in Klaviyo. |
| 314 | + ```typescript |
| 315 | + import { OAuthApi } from 'klaviyo-api' |
| 316 | + |
| 317 | + const oauthApi = new OAuthApi("<client id>", "<client secret>", <TokenStorage implementation instance>) |
| 318 | + oauthApi.generateAuthorizeUrl( |
| 319 | + state, // It's suggested to use your internal identifier for the Klaviyo account that is authorizing |
| 320 | + scopes, |
| 321 | + codeChallenge, |
| 322 | + redirectUrl |
| 323 | + ) |
| 324 | + ``` |
| 325 | +2. `createTokens` - Uses Klaviyo `/oauth/token/` endpoint to create `access` and `refresh` tokens |
| 326 | + 1. `customerIdentifier` - This ID is NOT sent to Klaviyo's API. If the `/token` API call this method wraps is successful, the created tokens will be passed into your `save` method along with this `customerIdentifier` in your implementation of `TokenStorage`. |
| 327 | + 2. `codeVerifier` - The verifier code must match the challenge code in the authorized URL redirect. |
| 328 | + 3. `authorizationCode`- A User approving your integration creates this temporary authorization code. Your specified redirect URL receives this under a `code` query parameter. |
| 329 | + 4. `redirectUrl` - The endpoint set in `generateAuthorizeUrl`. Whitelist the URL in your application settings. |
| 330 | + |
| 331 | + ```typescript |
| 332 | + import { OAuthApi } from 'klaviyo-api' |
| 333 | +
|
| 334 | + const oauthApi = new OAuthApi("<client id>", "<client secret>", <TokenStorage implementation instance>) |
| 335 | + await oauthApi.createTokens( |
| 336 | + customerIdentifier, |
| 337 | + codeVerifier, |
| 338 | + authorizationCode, |
| 339 | + redirectUrl |
| 340 | + ) |
| 341 | + ``` |
| 342 | +3. `OAuthCallbackQueryParams` For typescript users, this object is an interface representing the possible query parameters sent to your redirect endpoint |
| 343 | + |
| 344 | + |
| 345 | + |
| 346 | +#### Proof Key of Code Exchange (PKCE) |
| 347 | + |
| 348 | +All the PKCE helper functions live within the `Pkce` namespace. Read about PKCE [here](https://help.klaviyo.com/hc/en-us/articles/18819413031067#h_01HACEKGF3AZ2KFGVPSSZNR5QW) |
| 349 | + |
| 350 | +```typescript |
| 351 | +import { Pkce } from 'klaviyo-api' |
| 352 | +``` |
| 353 | + |
| 354 | +The `Pkce` namespace holds two different helper utilities |
| 355 | +1. `generateCodes` - This method will create the `codeVerifier` and `codeChallenge` needed later in the authorization flow. |
| 356 | + |
| 357 | + ```typescript |
| 358 | + import { Pkce } from 'klaviyo-api' |
| 359 | + |
| 360 | + const pkceCodes = new Pkce.generateCodes() |
| 361 | + // the two codes can be accessed by |
| 362 | + const codeVerifier: string = pkceCodes.codeVerifier |
| 363 | + const codeChallenge: string = pkceCodes.codeChallenge |
| 364 | + ``` |
| 365 | + |
| 366 | +2. `CodeStorage` - This is an OPTIONAL interface to help keep your code organized, to relate a `customerIdentifier` to their generated PKCE code |
| 367 | + |
| 368 | + ```typescript |
| 369 | + import { Pkce } from 'klaviyo-api' |
| 370 | + class <Your Code Storage Class Here> implements Pkce.CodeStorage |
| 371 | + ``` |
| 372 | +
|
209 | 373 | ## Optional Parameters and [JSON:API](https://jsonapi.org/) features |
210 | 374 |
|
211 | 375 | Here we will go over |
|
0 commit comments