At this stage of the tutorial series, you should have registered your app with Mailchimp and have OAuth set up in your app. In Mailchimp, you created at least one audience with a subscriber. The subscriber's email address should match the email of your person contact in Zendesk Sell.

In this tutorial, you'll add extra features to your app. The app will make authorized requests to the Mailchimp API to get audiences and then display them in a list.

This tutorial covers the following steps:

This tutorial is part of a series on building a Zendesk app:

Getting a person email address from Sell

You'll be retrieving audiences that a person contact subscribes to using Mailchimp lists endpoint.

GET https://server.api.mailchimp.com/3.0/lists?email=<EMAIL>

First, you'll get a person's email address from Sell and pass it as a query parameter. You could use the useSellContactEmail hook, but since the app supports one location (person_card), a simplified version can be created.

The useClientGet hook provided by the Sell ZAF app toolbox package will be used. It uses the Apps framework client.get() method to get data asynchronously for a given path.

The useClientGet hook returns an object with data, error, and feedback properties which have different values depending on the state of a request. The structure works well with the <ResponseHandler/> component mentioned in Reviewing the template files in part 2 of the tutorial series.

If a request isn’t completed yet, the hook returns:

{data: null, error: null, feedback: {status: "loading"}}

If the request is completed successfully, it returns response data and updates a feedback status:

{  data: {    firstName: "Ewen",    lastName: "Marin",    email: "[email protected]",    name: "Ewen Marin",    ....  }  error: null  feedback: {status: "success"}}

Get the email address from Sell

  1. Restart the app and the ZCLI server to be able to test it locally. For more information, refer back to Developing the app locally in the Part 2: Installing the app in Zendesk Sell.

    Note: In Part 3: OAuth 2.0 setup , you added an access token as an OAuth parameter to the manifest.json file. If you are requested to type it while running the ZCLI server, ignore it and click Enter. It won’t affect your app.

    In the Apps Sell API for person_card location, you can access the contact object. One of the contact object properties is an email address you retrieve with client.get('contact.email'). Try this out using the hook.

  2. In the EntryView.tsx file (src/EntryView.tsx), replace the <EntryView/> component with the following:

    export const EntryView = () => {  useClientHeight(230)  const contactEmailResponse = useClientGet('contact.email')
      return (    <Grid gutters={false} className={css.App}>      <Row>        <ResponseHandler          response={contactEmailResponse}          loadingView={<Loader />}          errorView={<div>Something went wrong!</div>}         emptyView={<div>There's nothing to see yet.</div>}        >          {([email]: [string]) => (            <Col textAlign="center">              <Header contactEmail={email} />              <ContentView />            </Col>          )}        </ResponseHandler>      </Row>    </Grid>  )}
  3. Save the file and refresh the app in your web browser. The email should be still there.

Working with authorized requests

Since you’ll be calling the Mailchimp API a few times, this logic will be extracted to a new helper method. We can leverage the existing helper useClientRequest and pass extra options to make an authorized request.

useClientRequest makes an HTTP request using the Apps framework. It uses the client.request() method which is the recommended method to make requests which are proxied to interpolate OAuth access tokens. It takes the URL of the resource as the first argument in the request. If you need to send additional parameters with the request, you can define them as a second argument.

The structure of the response is the same as for the useClientGet hook that you're using in the Getting a person email address from Sell.

Create an authorized request

  1. Create a hooks folder in the src directory.

  2. Create a useClientAuthorizedRequest.tsx file inside it. Add the following code to the file and save it:

    import {useClientRequest, Response} from '@zendesk/sell-zaf-app-toolbox'
    /* parameter of type 'oauth' should exist in the manifest.json file {   "name" : "access_token",   "type": "oauth" } */ export default function useClientAuthorizedRequest<T extends {}>(   url: string,   options: object = {},   dependencies?: any[], ): Response<T> { const response = useClientRequest<T>(   url,   {     secure: true,     headers: {authorization: 'OAuth {{setting.access_token}}'},     dataType: 'json',     contentType: 'application/json',     ...options,   },   dependencies,   )   return response }

As discussed in Part 3: OAuth 2.0 setup in the "Configuring an app in the manifest" section, you have to include the following properties to a call request to a third-party service - secure: true and authorization header set to OAuth {{setting.access_token}}.

With this setup, you can make your first request to the Mailchimp API.

Retrieving a server prefix from Mailchimp

The created useClientAuthorizedRequest hook will be used to get information about the user who granted OAuth access. Specifically, you get the user's server prefix which is needed to make calls to the Mailchimp API on the user’s behalf. This prefix will change from user to user. To retrieve the server prefix, a GET request is sent to Mailchimp's metadata endpoint:

https://login.mailchimp.com/oauth2/metadata

Retrieve server prefix from Mailchimp

  1. Create another hook in the useMailchimpMetadata.tsx file /src/hooks/ directory with the following content:

    import {Response} from '@zendesk/sell-zaf-app-toolbox'import useClientAuthorizedRequest from './useClientAuthorizedRequest'import {LoginMetadata} from '../types'
    export default function useMailchimpMetadata(): Response<LoginMetadata> {  return useClientAuthorizedRequest<LoginMetadata>(    'https://login.mailchimp.com/oauth2/metadata',    {},    [],  )}
  2. Since you're using TypeScript in the project, create a types.ts file in the src/ directory and add the following types so the hook is statically typed.

    export interface Login {  email: string  avatar?: any  login_id: number  login_name: string  login_email: string}
    export interface MailchimpMeta {  dc: string  role: string  accountname: string  user_id: number  login: Login  login_url: string  api_endpoint: string}
    export interface LoginMetadata {  data?: MailchimpMeta}
  3. Call the useMailchimpMetadata hook from the <EntryView/> component.

    // other imports import useMailchimpMetadata from './hooks/useMailchimpMetadata'
     export const EntryView = () => {   ... // other hooks   const mailchimpMetadataResponse = useMailchimpMetadata() // server prefix request
       return ... }
  4. Save the files.

  5. Go to Sell and open the Developer Tools by using the one of the shortcuts depending on your browser.

    • Google Chrome: Option + + J (on macOS), or Shift + CTRL + J (on Windows/Linux)
    • Firefox: Option + + I (on macOS), or Shift + CTRL + I or F12 (on Windows/Linux)
  6. Click the Network tab to observe requests.

  7. Refresh the app. When the app is loaded, look for the Mailchimp metadata request in the Network tab. The request should succeed with a status 200 response.

  8. Switch to the Preview tab to check the response. Look for the api_endpoint.

The server prefix will be used in the next section to fetch audiences.

Fetching audiences from Mailchimp

We have all the information required to fetch audiences for a given person.

Fetch audiences from Mailchimp

  1. Create useAudiences.tsx file in the /src/hooks/ directory and add the following code:

    import {Response} from '@zendesk/sell-zaf-app-toolbox'
    import useClientAuthorizedRequest from './useClientAuthorizedRequest'import {MailchimpLists} from '../types'
    const useAudiences = ({  email,  apiEndpoint,}: {  email: string  apiEndpoint: string}): Response<MailchimpLists> => {  const url = `${apiEndpoint}/3.0/lists?email=${email}&sort_field=date_created`  return useClientAuthorizedRequest<MailchimpLists>(url, {}, [])}
    export default useAudiences

    The useAudiences hook takes email and apiEndpoint (server prefix) which are required to compose the correct lists url.

  2. Add the following types to the types.ts file:

    export interface Constraints {   may_create: boolean   max_instances: number   current_total_instances: number }
     export interface ListStats {   member_count: number   unsubscribe_count: number   cleaned_count: number   member_count_since_send: number   unsubscribe_count_since_send: number   cleaned_count_since_send: number   campaign_count: number   campaign_last_sent: string   merge_field_count: number   avg_sub_rate: number   avg_unsub_rate: number   target_sub_rate: number   open_rate: number   click_rate: number   last_sub_date: any   last_unsub_date: string }
     export interface Contact {   company: string   address1: string   address2: string   city: string   state: string   zip: string   country: string   phone: string }
     export interface CampaignDefaults {   from_name: string   from_email: string   subject: string   language: string }
     export interface Link {   rel: string   href: string   method: string   targetSchema?: string   schema?: string }
     export interface List {   id: string   web_id: number   name: string   contact: Contact   permission_reminder: string   use_archive_bar: boolean   campaign_defaults: CampaignDefaults   notify_on_subscribe: string   notify_on_unsubscribe: string   date_created: Date   list_rating: number   email_type_option: boolean   subscribe_url_short: string   subscribe_url_long: string   beamer_address: string   visibility: string   double_optin: boolean   has_welcome: boolean   marketing_permissions: boolean   modules: any[]   stats: ListStats   _links: Link[] }
     export interface MailchimpLists {   lists: List[]   total_items: number   constraints: Constraints   _links: Link[] }

    Next, you'll to call the useAudiences hook in a new <AudiencesList/> component which is responsible for displaying audiences from the lists request. Take a look at JSON success example response to get familiar with the data structure.

    We'll be iterating audiences, showing an audience name (audience.name) and a the number of subscribers (audience.stats.member_count) for a single item.

  3. Create AudiencesList.tsx file in src/components/ folder with the following content:

    import * as React from 'react'
     import {Row} from '@zendeskgarden/react-grid' import {ResponseHandler} from '@zendesk/sell-zaf-app-toolbox' import ListStroke from '@zendeskgarden/svg-icons/src/16/clipboard-list-stroke.svg'
     import useAudiences from '../hooks/useAudiences' import {List} from '../types'
     import css from '../App.css'
     interface AudiencesListProps {   email: string   apiEndpoint: string }
     const Audience = ({audience}: any) => {   return (     <div className={css.audience}>       <div className={css.title}>{audience.name}</div>       <p>Member count: {audience.stats.member_count}</p>     </div>   ) }
     const AudiencesList = ({email, apiEndpoint}: AudiencesListProps) => {   const audiencesResponse = useAudiences({email, apiEndpoint})
       return (     <>       <Row justifyContent="center" className={css.header}>         <div className={css.icon}>           <ListStroke />         </div>         <div className={css.title}>Audiences</div>       </Row>       <Row>         <ResponseHandler           response={audiencesResponse}           errorView={<div>Something went wrong!</div>}           emptyView={<div>There's nothing to see yet.</div>}         >           {([{lists}]) => {             return lists.map((list: List, index: number) => (               <Audience key={index} audience={list} />             ))           }}         </ResponseHandler>       </Row>     </>   ) }
     export default AudiencesList
  4. Add the following rules to the App.css file to style the audiences list:

    .audience {  border-bottom: solid 1px var(--zd-color-grey-300);  overflow: hidden;  display: block;  width: 100%;  padding: var(--zd-spacing-sm);}
    .icon {  margin-right: var(--zd-spacing-xs);}
  5. Update the <EntryView/> component in src/EntryView.tsx to display the audiences list as well as deliver the subscriber email and your server prefix:

    // other imports import {MailchimpMeta} from './types' import AudiencesList from './components/AudiencesList'
     export const EntryView = () => {   ... // other hooks   const mailchimpMetadataResponse = useMailchimpMetadata()
       return (     <Grid gutters={false} className={css.App}>       <Row>         <ResponseHandler           responses={[contactEmailResponse, mailchimpMetadataResponse]}           loadingView={<Loader />}           errorView={<div>Something went wrong!</div>}           emptyView={<div>There's nothing to see yet.</div>}         >           {([email, mailchimpMetadata]: [string, MailchimpMeta]) => (             <Col>               <AudiencesList                 email={email}                 apiEndpoint={mailchimpMetadata.api_endpoint}               />             </Col>           )}         </ResponseHandler>       </Row>     </Grid>   ) }

    The <ResponseHandler/> component takes an array of responses and display its children when all requests are completed.

  6. Go to your web browser and refresh the app in your Sell instance. You should see a list of audiences to which your person contact in Sell subscribes.

Congratulations! You’ve created the app with a working OAuth flow.

Next steps

The best way to learn is to plan, design, and build your own apps. You can use any of the following resources:

  • Getting started - A quick overview of the Apps framework
  • Setting up new apps - How to create starter files for your apps with ZCLI or use the ZAF React Skeleton for Sell Apps
  • Using the Apps framework - A concise developer guide
  • Deploying apps - Information on branding, uploading, and localizing your apps
  • ZAF Client API - A reference of the ZAF JavaScript client
  • ZAF Core API - A reference of core events, actions, and properties available in all locations in all products that support the Zendesk Apps framework
  • ZAF Sell API - A reference of the app locations, properties, and events you can use in apps running in Zendesk Sell
  • ZAF App Toolbox - A package which delivers a bunch of useful methods, hooks, and components to help you build React apps integrated with Zendesk Sell quicker and with less effort. It uses the Zendesk Apps framework (ZAF) Client .

You can also look for answers or ask questions in the Zendesk Apps framework (ZAF) community.