From 4023b577ec3c30775556f34e2b2387011a599311 Mon Sep 17 00:00:00 2001 From: Manas Verma Date: Sun, 8 Jan 2023 23:24:43 -0600 Subject: [PATCH 1/2] Adding simple tutorials on how to use Vessel --- docs/how-to-vessel.mdx | 152 +++++++++++++++++++++++++++++++++++++++++ docs/mint.json | 2 +- 2 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 docs/how-to-vessel.mdx diff --git a/docs/how-to-vessel.mdx b/docs/how-to-vessel.mdx new file mode 100644 index 0000000..847e6c6 --- /dev/null +++ b/docs/how-to-vessel.mdx @@ -0,0 +1,152 @@ +--- +title: "Things You Can Do With Vessel" +--- + +Here are a few examples of things that Vessel enables you to do. + +## Setup + +Before we get started, let's put down a very rough but +concrete version of what a client for Vessel's API would look like. + +```typescript +class VesselClient { + private apiToken: string; + private accessToken: string; + + constructor(apiToken: string, accessToken: string) { + this.apiToken = apiToken; + this.accessToken = accessToken; + } + + async makeRequest({ + objectType, + requestType, + data, + }: { + objectType: string; + requestType: string; + data?: Record; + }) { + const path : string = { + 'get-all': 's', + 'batch': '/batch', + 'details': '/details', + }[requestType] ?? ''; + + const method : string = { + 'get': 'GET', + 'get-all': 'GET', + 'batch': 'GET', + 'details': 'GET', + 'create': 'POST', + 'update': 'PATCH', + }[requestType]; + + const query = method === 'GET' ? `?${new URLSearchParams(data as Record)}` : ''; + + const response = await fetch( + `https://api.vessel.land/crm/${objectType}${path}${query}`, + { + method, + headers: { + 'vessel-api-token': this.apiToken, + }, + ...(method === 'GET' ? {} : + { + body: JSON.stringify({ + access_token: this.accessToken, + ...data, + }) + } + ), + } + ); + return await response.json(); + } +} + +const vessel = new VesselClient(API_TOKEN, ACCESS_TOKEN); +``` +We will use this generic `makeRequest` in each of our following examples to be explicit how we're making the calls. + +## Create a Lead +Let's say your app creates an amazing funnel that creates new leads for your users. You can automatically add them to your user's CRM's with this +```typescript +const createLead = async (firstName: string, + lastName: string, + email: string) => client.makeRequest({ + objectType: 'lead', + requestType: 'create', + data: { lead: { + firstName, lastName, email, + } }, +}); +``` + +## Add a Note for a Lead +For this example, let's say your app allows potential leads to provide feedback after a sales call. You would like to add this as a note in your user's CRM's attached to their lead entity. + +Let's first add functionality to find our lead object. +```typescript +const findLeadsWithEmail = async (email: string) => client.makeRequest({ + objectType: 'lead', + requestType: 'search', + data: { email } +}); +``` +And then add a function to create a note with the feedback we want. +```typescript +const createNote = async (user: YourUser, leadId: string, feedback: string) => client.makeRequest({ + objectType: 'note', + requestType: 'create', + data: { note: { + userId: user.vesselId, + leadId, + content: feedback, + } } +}); +``` +And finally +```typescript +async function updateLeadWithFeedback(user: YourUser, email: string, feedback: string) { + const { leads } = await findLeadsWithEmail(email); + const leadId = leads[0].id; + await createNote(user, leadId, feedback); +} +``` + +## Territory of a User +Say your app involves looking at all the locations a given user is assigned to. In this specific example, we will pull all postal codes for a user. + +First we will need all account ids associated with the user in question. +```typescript +const getAccountIdsFromUser = async (userId: string) => vessel.makeRequest({ + objectType: 'associations', + requestType: 'get', + data: { objectId: userId }, +}); +``` + +Then we will need to grab the full account objects from those ids. +```typescript +const getBatchAccounts = async (ids: string[]) => vessel.makeRequest({ + objectType: 'accounts', + requestType: 'batch', + data: { ids: ids.join(',') }, +}); +``` + +And finally we can put it all together and grab the postal codes for each account. +```typescript +async function getZipCodesForUser(user: YourUser) { + const { associations } = await getAccountIdsFromUser(user.vesselId); + const accountIds = associations.filter((a) => a.objectType === 'account').map((a) => a.objectId); + const { accounts } = await getBatchAccounts(accountIds); + return accounts.map((account) => account.address?.postalCode); +} +``` + +## Questions + +Is there anything you're wondering if Vessel can accomplish for your company? Send us an email at [support@vessel.land](support@vessel.land) and we'll be more than happy to help! \ No newline at end of file diff --git a/docs/mint.json b/docs/mint.json index b17ba99..da0369d 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -36,7 +36,7 @@ }, { "group": "How-To Guides", - "pages": ["getting-started", "accessing-native-data"] + "pages": ["getting-started", "how-to-vessel", "accessing-native-data"] }, { "group": "References", From 8d4e281959a84407987d6c478434216fe4356359 Mon Sep 17 00:00:00 2001 From: Manas Verma Date: Sat, 14 Jan 2023 21:55:24 -0600 Subject: [PATCH 2/2] Updating examples and wording --- docs/examples.mdx | 160 +++++++++++++++++++++++++++++++++++++++++ docs/how-to-vessel.mdx | 152 --------------------------------------- docs/mint.json | 2 +- 3 files changed, 161 insertions(+), 153 deletions(-) create mode 100644 docs/examples.mdx delete mode 100644 docs/how-to-vessel.mdx diff --git a/docs/examples.mdx b/docs/examples.mdx new file mode 100644 index 0000000..e54adb5 --- /dev/null +++ b/docs/examples.mdx @@ -0,0 +1,160 @@ +--- +title: "Examples" +--- + +Here are a few examples of what Vessel empowers you to do. Each example +below consists of a real use-case that your company might be able to +provide for your users! + +## Add a Note for a Lead +Notes are a great way to include information in your users' CRMs. +For this example, we're creating a survey process for leads after +a sales call. The sales rep will be able to see this as an attached +note to the lead. + +The app will take in the lead's email, so we can use that to +make our search. +```typescript +const findLeadsWithEmail = async (email: string) => vessel.makeRequest({ + objectType: 'Lead', + requestType: 'search', + data: { email } +}); +``` + +Now that we have the lead, lets create a Note object and pass in the +lead id. +```typescript +const createNote = async (user: YourUser, leadId: string, feedback: string) => vessel.makeRequest({ + objectType: 'Note', + requestType: 'create', + data: { note: { + userId: user.vesselId, + leadId, + content: feedback, + } } +}); +``` +And finally +```typescript +async function updateLeadWithFeedback(user: YourUser, email: string, feedback: string) { + const { leads } = await findLeadsWithEmail(email); + const leadId = leads[0].id; + await createNote(user, leadId, feedback); +} +``` + +## Territory of a User +It's often useful to know the territories a user is assigned to. For this +example we will grab all the zip codes for the Accounts a given user +is assigned to. + +First we will need all account ids associated with the user in question. +Most Vessel objects have an associations array you can pull from, however, +`User` objects require a separate endpoint, since they tend to be highly +associated. +```typescript +const getAccountIdsFromUser = async (userId: string) => vessel.makeRequest({ + objectType: 'associations', + requestType: 'get', + data: { objectId: userId }, +}); +``` + +Now lets make a batch request with the account ids. +```typescript +const getBatchAccounts = async (ids: string[]) => vessel.makeRequest({ + objectType: 'accounts', + requestType: 'batch', + data: { ids: ids.join(',') }, +}); +``` + +Putting it together we can grab all the zip codes for a user. +```typescript +async function getZipCodesForUser(user: YourUser) { + const { associations } = await getAccountIdsFromUser(user.vesselId); + const accountIds = associations.filter((a) => a.objectType === 'account').map((a) => a.objectId); + const { accounts } = await getBatchAccounts(accountIds); + return accounts.map((account) => account.address?.postalCode); +} +``` + +## Calendar Prep +For this example, we're going to build an extension that automatically +provides Account details to a calendar event. + +Your extension has access to the Event subject, so lets use that to +grab the event object itself. +```typescript +async function getEvent(subject: string) { + const { events } = await vessel.makeRequest({ + objectType: 'Event', + requestType: 'search', + data: { subject }, + }); + return events[0]; +} +``` + +Now one way to figure out which company this event is with is by +looking at the attendees and their email addresses. +We can grab all attendees for an event + +```typescript +async function getAccoountDetails(event: VesselEvent) { + const attendeeIds = event.associations.eventAttendeeIds; + const { eventAttendees: VesselEventAttendee[] } = await vessel.makeRequest({ + objectType: 'EventAttendee', + requestType: 'batch', + data: { ids: attendeeIds.join(',') }, + }); + // Grab all the domains from the attendee emails. + const domains = eventAttendees.map((attendee) => attendee.email?.split('@')[1]) + .filter((d) => d && d !== YOUR_DOMAIN); + // Grab the domain who has the most attendees that is not your domain. + const accountDomain = mode(domains); + // Grab the account with that domain. + const { accounts } = await vessel.makeRequest({ + objectType: 'Account', + requestType: 'search', + data: { url: { + contains: accountDomain, + } }, + }); + const account = first(accounts); + + if (!account) { + throw new Error('Could not find account for event'); + } + + return pick(account, ['description', 'industry']); +} +``` + +Now all those sales reps invited to the event will have +details about the account right away. Let's be a little bit more helpful +and add some related notes to the event as well. +```typescript +async function getAccountNotes(account: VesselAccount) { + const noteIds = account.associations.noteIds; + if (noteIds.length === 0) { + return []; + } + + const { notes } = await vessel.makeRequest({ + objectType: 'Note', + requestType: 'batch', + data: { ids: noteIds.join(',') }, + }); + + return notes.map((note) => note.content); +} +``` + + +## Questions + +Is there anything you're wondering if Vessel can accomplish for your +company? Send us an email at [support@vessel.land](support@vessel.land) +and we'll be more than happy to help! diff --git a/docs/how-to-vessel.mdx b/docs/how-to-vessel.mdx deleted file mode 100644 index 847e6c6..0000000 --- a/docs/how-to-vessel.mdx +++ /dev/null @@ -1,152 +0,0 @@ ---- -title: "Things You Can Do With Vessel" ---- - -Here are a few examples of things that Vessel enables you to do. - -## Setup - -Before we get started, let's put down a very rough but -concrete version of what a client for Vessel's API would look like. - -```typescript -class VesselClient { - private apiToken: string; - private accessToken: string; - - constructor(apiToken: string, accessToken: string) { - this.apiToken = apiToken; - this.accessToken = accessToken; - } - - async makeRequest({ - objectType, - requestType, - data, - }: { - objectType: string; - requestType: string; - data?: Record; - }) { - const path : string = { - 'get-all': 's', - 'batch': '/batch', - 'details': '/details', - }[requestType] ?? ''; - - const method : string = { - 'get': 'GET', - 'get-all': 'GET', - 'batch': 'GET', - 'details': 'GET', - 'create': 'POST', - 'update': 'PATCH', - }[requestType]; - - const query = method === 'GET' ? `?${new URLSearchParams(data as Record)}` : ''; - - const response = await fetch( - `https://api.vessel.land/crm/${objectType}${path}${query}`, - { - method, - headers: { - 'vessel-api-token': this.apiToken, - }, - ...(method === 'GET' ? {} : - { - body: JSON.stringify({ - access_token: this.accessToken, - ...data, - }) - } - ), - } - ); - return await response.json(); - } -} - -const vessel = new VesselClient(API_TOKEN, ACCESS_TOKEN); -``` -We will use this generic `makeRequest` in each of our following examples to be explicit how we're making the calls. - -## Create a Lead -Let's say your app creates an amazing funnel that creates new leads for your users. You can automatically add them to your user's CRM's with this -```typescript -const createLead = async (firstName: string, - lastName: string, - email: string) => client.makeRequest({ - objectType: 'lead', - requestType: 'create', - data: { lead: { - firstName, lastName, email, - } }, -}); -``` - -## Add a Note for a Lead -For this example, let's say your app allows potential leads to provide feedback after a sales call. You would like to add this as a note in your user's CRM's attached to their lead entity. - -Let's first add functionality to find our lead object. -```typescript -const findLeadsWithEmail = async (email: string) => client.makeRequest({ - objectType: 'lead', - requestType: 'search', - data: { email } -}); -``` -And then add a function to create a note with the feedback we want. -```typescript -const createNote = async (user: YourUser, leadId: string, feedback: string) => client.makeRequest({ - objectType: 'note', - requestType: 'create', - data: { note: { - userId: user.vesselId, - leadId, - content: feedback, - } } -}); -``` -And finally -```typescript -async function updateLeadWithFeedback(user: YourUser, email: string, feedback: string) { - const { leads } = await findLeadsWithEmail(email); - const leadId = leads[0].id; - await createNote(user, leadId, feedback); -} -``` - -## Territory of a User -Say your app involves looking at all the locations a given user is assigned to. In this specific example, we will pull all postal codes for a user. - -First we will need all account ids associated with the user in question. -```typescript -const getAccountIdsFromUser = async (userId: string) => vessel.makeRequest({ - objectType: 'associations', - requestType: 'get', - data: { objectId: userId }, -}); -``` - -Then we will need to grab the full account objects from those ids. -```typescript -const getBatchAccounts = async (ids: string[]) => vessel.makeRequest({ - objectType: 'accounts', - requestType: 'batch', - data: { ids: ids.join(',') }, -}); -``` - -And finally we can put it all together and grab the postal codes for each account. -```typescript -async function getZipCodesForUser(user: YourUser) { - const { associations } = await getAccountIdsFromUser(user.vesselId); - const accountIds = associations.filter((a) => a.objectType === 'account').map((a) => a.objectId); - const { accounts } = await getBatchAccounts(accountIds); - return accounts.map((account) => account.address?.postalCode); -} -``` - -## Questions - -Is there anything you're wondering if Vessel can accomplish for your company? Send us an email at [support@vessel.land](support@vessel.land) and we'll be more than happy to help! \ No newline at end of file diff --git a/docs/mint.json b/docs/mint.json index da0369d..9a40b1c 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -36,7 +36,7 @@ }, { "group": "How-To Guides", - "pages": ["getting-started", "how-to-vessel", "accessing-native-data"] + "pages": ["getting-started", "examples", "accessing-native-data"] }, { "group": "References",