> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.com/ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Salesforce Opportunities

> Use OpenAI, NextJS, and the Auth0-AI SDKs to get Salesforce opportunities

export const AccountLinking = ({connectionLabel = "any Identity Provider"}) => <>
    <h2>Account Linking</h2>
    <p>
      If you're integrating with {connectionLabel} and want users to be able to sign in using a different
      method (e.g., username and password or another external provider), you need to link
      these identities into a single user account. Auth0 refers to this process as{" "}
      <a href="https://auth0.com/docs/manage-users/user-accounts/user-account-linking">
        Account Linking
      </a>
      .
    </p>
    <p>
      Account Linking is separate from{" "}
      <a href="https://auth0.com/docs/secure/tokens/token-vault/connected-accounts-for-token-vault">
        Connected Accounts for Token Vault
      </a>
      :
    </p>
    <ul>
      <li>Account Linking merges multiple Auth0 identities into one user profile for sign-in.</li>
      <li>
        Connected Accounts for Token Vault allows that signed-in user to authorize an external
        provider so Auth0 can store the provider's tokens in Token Vault.
      </li>
    </ul>
    <p>
      If your application uses{" "}
      <a href="https://auth0.com/docs/manage-users/organizations">Organizations</a>, authenticate the
      user with the target organization before initiating the Connected Accounts flow. Organizations
      define the session context; they do not create a shared external account for the organization.
    </p>
    <p>
      Account Linking logic and handling varies depending on your app or agent.
      You can find an example of how to implement it in a{" "} <a href="https://github.com/auth0-lab/market0/blob/main/app/api/auth/%5Bauth0%5D/route.ts#L43">Next.js chatbot app</a>
      . If you have questions or are looking for best practices,{" "}
      <a href="http://discord.gg/XbQpZSF2Ys">join our Discord</a> and ask in the{" "}
      <code>#auth0-for-gen-ai</code> channel.
    </p>
  </>;

export const CustomApiClient = ({apiName = "the external API"}) => {
  return <Step title="Create a Custom API Client in Auth0">
      The Custom API Client allows your API server to perform token exchanges
      using{" "}
      <strong>
        <i>access tokens</i>
      </strong>{" "}
      instead of{" "}
      <strong>
        <i>refresh tokens</i>
      </strong>
      . This client enables Token Vault to exchange an access token for an
      external API access token (e.g., {apiName}).
      <br />
      <ul>
        <li>
          Navigate to <strong>Applications &gt; APIs</strong>
        </li>
        <li>
          Click the <strong>Create API</strong> button to create a new Custom
          API.
        </li>
        <li>
          Go to the Custom API you created and click the{" "}
          <strong>Add Application</strong> button in the right top corner.
        </li>
        <li>
          Once you've added the API as an application, click the <strong>Configure Application</strong> button
          in the right top corner.
        </li>
        <li>
          Note down the <code>client id</code> and <code>client secret</code>{" "}
          for your environment variables.
        </li>
      </ul>
    </Step>;
};

export const SalesforcePrereqs = ({lang, createCustomApiClientStep = false}) => {
  const languageSteps = [];
  if (lang === "js") {
    languageSteps.push(<Step title={<>
            Install Node.js 20+ and <code>npm</code>
          </>} />);
  } else if (lang === "python") {
    languageSteps.push(<Step title={<>
            Install Python 3.11+ and <code>pip</code>
          </>} />);
  }
  const commonSteps = [<Step title={<>
          Complete the{" "}
          <a href="/ai/docs/get-started/user-authentication">
            User authentication quickstart
          </a>{" "}
          to create an application integrated with Auth0.
        </>} />, <Step title={<>
          <a href="https://platform.openai.com/docs/quickstart?api-mode=chat" target="_blank" rel="noopener noreferrer">
            Set up an OpenAI API key
          </a>
          .
        </>} />, <Step title={<>
          Set up and configure a Salesforce instance with an{" "}
          <a href="https://help.salesforce.com/s/articleView?id=xcloud.external_client_apps.htm&amp;type=5" target="_blank" rel="noopener noreferrer">
            External Client App
          </a>
          .
        </>} />, <Step title={<>
          Set the <code>SALESFORCE_INSTANCE_URL</code> in your <code>.env</code>{" "}
          file
        </>}>
      <pre>
        <code>
          SALESFORCE_INSTANCE_URL=https://your-instance.salesforce.com
        </code>
      </pre>
    </Step>, <Step title={<>
          <a href="https://auth0.com/docs/authenticate/identity-providers/enterprise-identity-providers/oidc" target="_blank" rel="noopener noreferrer">
            Configure a Salesforce OIDC connection
          </a>{" "}
          in Auth0.
        </>}>
      <ul>
        <li>
          Under the <strong>General</strong> section, ensure the following{" "}
          <strong>Scopes</strong>:
          <ul>
            <li>
              <code>openid</code>
            </li>
            <li>
              <code>api</code>
            </li>
            <li>
              <code>refresh_token</code>
            </li>
            <li>
              <code>offline_access</code>
            </li>
          </ul>
        </li>
        <li>
          Under the <strong>Purpose</strong> section, make sure to enable the{" "}
          <code>Use for Connected Accounts with Token Vault</code> toggle.
        </li>
      </ul>
    </Step>];
  if (createCustomApiClientStep) {
    const step = CustomApiClient({
      apiName: "Salesforce API"
    });
    commonSteps.push(step);
  }
  return <>
      <Heading level={3} id="prerequisites">
        Prerequisites
      </Heading>
      Before getting started, make sure you have completed the following steps:
      <Steps>{[...languageSteps, ...commonSteps]}</Steps>
    </>;
};

<Tabs>
  <Tab title="Next.js" icon="https://mintlify-assets.b-cdn.net/auth0/nextjs-svgrepo-com.svg">
    <SalesforcePrereqs lang="js" />

    ## 1. Define the Vercel AI tool and backend API route

    Create an AI tool that gets a list of opportunities from Salesforce and a backend route that uses Auth0 to get a Salesforce access token:

    * When the tool calls `auth0.getAccessTokenForConnection()`, pass `sfdc` as the connection name to get a Salesforce access token.

    ```tsx app/api/chat/route.js wrap lines theme={null}
    import { openai } from "@ai-sdk/openai";
    import { streamText, tool } from "ai";
    import { z } from "zod";
    import { auth0 } from "@/lib/auth0";

    export const maxDuration = 60;

    export async function POST(req) {
      const { messages } = await req.json();

      const system = `You're a helpful AI agent that helps analyze salesforce data`;

      const response = streamText({
        model: openai("gpt-4o"),
        messages,
        system,
        maxSteps: 10,
        tools: {
          listOpportunities: tool({
            // salesforce tool call to get a list of opportunities
            description: "Get a list of opportunities from Salesforce",
            parameters: z.object({
              limit: z
                .number()
                .default(10)
                .describe("The maximum number of opportunities to return"),
            }),
            execute: async ({ limit }) => {
              const instanceUrl = process.env.SALESFORCE_INSTANCE_URL;

              const endpoint = `query/?q=${encodeURIComponent(
                `SELECT Id, Name, StageName, CloseDate FROM Opportunity LIMIT ${limit}`
              )}`;
              const url = `${instanceUrl}/services/data/v57.0/${endpoint}`;

              // call auth0 to get the access token
              const { accessToken } = await auth0.getAccessTokenForConnection({
                connection: "sfdc",
              });

              const response = await fetch(url, {
                method: "GET",
                headers: {
                  Authorization: `Bearer ${accessToken}`,
                  "Content-Type": "application/json",
                },
              });
              return await response.json();
            },
          }),
        },
      });
      return response.toDataStreamResponse();
    }
    ```

    ## 2. Call from the frontend Chat UI

    Use the `@ai-sdk/react` hook to wire up the chat component:

    ```tsx src/components/chat.tsx wrap lines theme={null}
    "use client";
    import { useChat } from "@ai-sdk/react";
    export default function Chat() {
      const { messages, input, handleInputChange, handleSubmit } = useChat();
      return (
        <div className="flex flex-col w-full max-w-3xl py-24 mx-auto stretch text-gray-100">
          {messages.map((message) => (
            <div key={message.id} className="whitespace-pre-wrap">
              {message.role === "user" ? "User: " : "AI: "}
              {message.parts.map((part, i) => {
                switch (part.type) {
                  case "text":
                    return <div key={`${message.id}-${i}`}>{part.text}</div>;
                }
              })}
            </div>
          ))}
          <form onSubmit={handleSubmit}>
            <input
              className="fixed bottom-0 w-full max-w-3xl p-2 mb-8 border border-zinc-300 rounded shadow-xl"
              value={input}
              placeholder="Say something..."
              onChange={handleInputChange}
            />
          </form>
        </div>
      );
    }
    ```

    ## 3. Example UI

    Navigate to `https://localhost:3000` to see the chat UI:

    {" "}

    <Frame>
      <img
        src="https://mintlify.s3.us-west-1.amazonaws.com/auth0-genai/img/get_salesforce_opportunities_chat_ui.png"
        alt="Get Salesforce Opportunities Chat
UI"
      />
    </Frame>

    You can customize the chat UI to display structured results in tables, charts, or summaries. When the user sends a message like `Get me 2 opportunities from Salesforce`, GPT-4 interprets the request and invokes the `listOpportunities` tool, which securely calls the Salesforce API using access tokens obtained via Auth0 and returns the results.
  </Tab>

  <Tab title="LangChain" icon="https://mintlify-assets.b-cdn.net/auth0/langchain.svg" disabled={true}>
    Coming soon!
  </Tab>

  <Tab title="LlamaIndex" icon="https://mintlify-assets.b-cdn.net/auth0/llamadex.svg" disabled={true}>
    Coming soon!
  </Tab>

  <Tab title="GenKit" icon="https://mintlify-assets.b-cdn.net/auth0/genkit.svg" disabled={true}>
    Coming soon!
  </Tab>
</Tabs>

<AccountLinking connectionLabel="Salesforce" />
