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

# Construa seu próprio popup de vinculação

> Modo direto (Direct Mode) — conecte uma rede de cada vez a partir do seu próprio botão, com um popup que você mesmo abre e observa.

export const PlansAvailable = ({plans = [], maxPackRequired}) => {
  let displayPlans = plans;
  if (plans && plans.length === 1) {
    const lowerCasePlan = plans[0].toLowerCase();
    if (lowerCasePlan === "business") {
      displayPlans = ["Launch", "Business", "Enterprise"];
    } else if (lowerCasePlan === "premium") {
      displayPlans = ["Premium", "Launch", "Business", "Enterprise"];
    }
  }
  return <Note>
Available on {displayPlans.length === 1 ? "the " : ""}
{displayPlans.join(", ").replace(/\b\w/g, l => l.toUpperCase())}{" "}
{displayPlans.length > 1 ? "plans" : "plan"}.

{maxPackRequired && <span onClick={() => window.open('https://www.ayrshare.com/docs/additional/maxpack', '_self')} className="flex items-center mt-2 cursor-pointer">
 <span className="px-1.5 py-0.5 rounded text-sm" style={{
    backgroundColor: '#C264B6',
    color: 'white',
    fontSize: '12px'
  }}>
   Max Pack required
 </span>
</span>}
</Note>;
};

<PlansAvailable plans={["business"]} maxPackRequired={true} />

O modo direto conecta **uma rede social de cada vez**, a partir de um botão no seu próprio dashboard. Você
cria uma link session para essa rede, abre a URL que ela retorna em um popup, e sua página ouve
o que aconteceu. Seu usuário nunca vê uma página listando todas as redes, e nunca sai do seu app por
mais tempo do que o login da própria rede leva.

## Qual superfície você quer

Três formatos, e os dois primeiros são a mesma integração. Esta página é a que você constrói
por conta própria.

| Superfície                                                                                                                         | O que seu usuário vê                                                           | White-label                                                                     | Escolha quando                                                                                                  |
| ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| **Widget — frames incorporados** ([mount](/docs/multiple-users/connect-widget#mount-a-slot))                                            | nossos botões inline no seu próprio layout; nenhum popup até o da própria rede | **O mais forte.** Sua página, suas fontes e cores, e seu usuário nunca sai dela | você tem um dashboard com uma linha por rede e quer que a vinculação aconteça ali mesmo. Max Pack.              |
| **Widget — seu próprio botão** ([popup](/docs/multiple-users/connect-widget#your-own-button))                                           | seu botão, depois um popup para a rede                                         | **Forte.** O popup é nosso, mas é breve e herda sua aparência                   | você quer seu próprio botão e estilo, e nenhum frame no seu layout. Max Pack.                                   |
| **Página de vinculação hospedada** ([como fazer](/docs/multiple-users/api-integration-business#single-sign-on-with-jwt-authentication)) | uma página que nós hospedamos, com seu logotipo, cores e CSS personalizado     | **O mais fraco.** É a nossa página, e seu usuário sai da sua para usá-la        | você quer um único link para distribuir, ou está fazendo onboarding por e-mail. Nada a construir, sem Max Pack. |

<Note>
  **O modo direto é o popup da terceira linha sem o nosso script.** Se a sua página pode carregar o script, o
  [widget](/docs/multiple-users/connect-widget) faz tudo desta página por você — ele mesmo abre e
  observa o popup, e também pode incorporar frames. O modo direto é o que você quer quando sua
  página não pode carregar um script de terceiros, ou quando a superfície é um app nativo em vez de um navegador.
</Note>

<Frame caption="Seu botão, sua página. O popup é a única coisa nossa que seu usuário vê, e apenas pelo tempo de que a rede precisa.">
  <img src="https://mintcdn.com/ayrshare-docs/-2tpx3mFy9vWIObd/images/multiple-users/connect-widget-popup.webp?fit=max&auto=format&n=-2tpx3mFy9vWIObd&q=85&s=b68021d477703d97a5994ee85d299be6" alt="Um dashboard de cliente com seus próprios botões Connect e um popup da Ayrshare mostrando a tela de transição do Facebook" width="2880" height="1317" data-path="images/multiple-users/connect-widget-popup.webp" />
</Frame>

## O que você constrói

Quatro passos. O primeiro é no seu servidor, os demais são na sua página.

<Steps>
  <Step title="Crie uma sessão para uma rede">
    A partir do seu backend, chame
    [Criar uma Link Session](/docs/apis/profiles/create-link-session) com `mode: "connect"`, o
    `network` e o `origin` em que a sua página roda.

    ```javascript Your backend theme={"system"}
    const response = await fetch("https://api.ayrshare.com/api/profiles/link-sessions", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${process.env.AYRSHARE_API_KEY}`,
        "Profile-Key": profileKey,
      },
      body: JSON.stringify({
        mode: "connect",
        network: "reddit",
        origin: "https://app.example.com",
      }),
    });

    const { url } = await response.json();
    ```

    Você recebe de volta uma `url` apontando para uma página de conexão de rede única, e nenhum `token` — o token está
    dentro da URL. Trate a URL inteira como uma senha: ela autentica seu usuário no User
    Profile dele.

    <Warning>
      Crie a sessão no seu servidor, nunca no navegador. A chamada precisa da sua API Key.
    </Warning>
  </Step>

  <Step title="Abra-a no handler de clique, de forma síncrona">
    O popup precisa ser aberto por `window.open` **no próprio handler de clique**. Um navegador só
    permite um popup enquanto ainda está processando o clique do seu usuário, e essa permissão não
    sobrevive a um `await` — então buscar a URL primeiro e abri-la no callback é confiavelmente
    bloqueado como popup.

    Busque a URL quando você renderiza o botão, ou quando seu usuário passa o mouse sobre ele. Na hora do clique você
    já deve tê-la.

    ```javascript Your page theme={"system"}
    // `url` was fetched earlier. Nothing async between the click and window.open.
    button.addEventListener("click", () => {
      const popup = window.open(url, "ayrshare-connect", "width=600,height=800");
      if (!popup) {
        showError("Allow popups for this site to connect an account.");
        return;
      }
      listenForOutcome(popup, url);
    });
    ```
  </Step>

  <Step title="Ouça o desfecho">
    Como você passou `origin`, o popup envia um evento à sua página para cada coisa que
    acontece nele: `connect:success`, `connect:error`, `connect:cancelled` e eventos de progresso
    no meio. Exatamente um desses três chega por conexão.

    [Eventos de conclusão de vinculação](/docs/multiple-users/link-completion-events) tem a tabela completa de eventos e um
    listener pronto para copiar e colar — `listenForOutcome` acima é esse snippet. Duas partes dele são fáceis de
    deixar de fora e as duas causam bugs reais:

    * **Verifique `event.origin`** contra a origem da URL que você abriu. Qualquer página pode enviar uma
      mensagem à sua janela, e a origem é a única parte de uma mensagem que não pode ser falsificada.
    * **Faça polling de `popup.closed`**, com uma pequena janela de tolerância antes de concluir qualquer coisa. Um popup
      que seu usuário fechou manualmente não envia absolutamente nada, e sem a janela de tolerância uma conexão
      bem-sucedida pode ser reportada como cancelada.
  </Step>

  <Step title="Trate cada desfecho">
    | Desfecho            | O que significa                                                                                         | O que fazer                                                                                                                     |
    | ------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
    | `connect:success`   | a conta está conectada **e salva**                                                                      | atualize essa linha. Um [`GET /user`](/docs/apis/user/profile-details) logo em seguida já a mostra.                                  |
    | `connect:error`     | a conexão falhou                                                                                        | mostre `message`. `code` está presente quando a falha tem um código catalogado e ausente quando não tem.                        |
    | `connect:cancelled` | seu usuário desistiu, ou fechou a janela                                                                | deixe a linha como estava. `reason` é `popupClosed`, `scopesDenied` ou `userCancelled`.                                         |
    | nada chega          | o link estava expirado, revogado ou é desconhecido, então a página nunca soube para onde enviar eventos | faça polling em [Consultar uma Link Session](/docs/apis/profiles/get-link-session), que reporta esses estados de forma autoritativa. |
  </Step>
</Steps>

<Tip>
  Adicione `&autoClose=false` à URL enquanto estiver construindo. O popup então permanece aberto após cada
  desfecho em vez de se fechar sozinho, para que você possa ler o que ele diz.
</Tip>

## Notas por rede

A maioria das redes é um popup e nada mais: seu usuário clica, autoriza na rede, e
o popup fecha. Estas são as exceções que valem conhecer antes de construir.

<AccordionGroup>
  <Accordion title="O X exige suas próprias API keys">
    O X em modo direto usa **suas** credenciais de X Developer App, fornecidas ao criar a
    sessão como os cabeçalhos `X-Twitter-OAuth1-Api-Key` e `X-Twitter-OAuth1-Api-Secret` em
    [Criar uma Link Session](/docs/apis/profiles/create-link-session).

    Uma sessão criada para `twitter` ou `x` **sem** esses cabeçalhos é recusada quando o popup
    abre: seu usuário é informado de que a conexão não está disponível e não vê formulário algum, e sua página
    recebe `connect:error` com uma `message` e **sem `code`**. Isso é deliberado. A credencial
    ausente é sua, não do seu usuário, e usuários finais nunca devem ser solicitados a digitar suas API keys.

    Compare com o Bluesky, onde a senha de app é uma credencial do próprio usuário final — essa a
    página de conexão coleta, sim, em um formulário dentro do popup.
  </Accordion>

  <Accordion title="O Facebook mostra um botão antes do login da Meta">
    `network: "facebook"` mostra um único botão no popup, e o login da própria Meta abre a partir
    desse clique — a Meta exige que seu login seja iniciado por um clique dentro da página que hospeda seu
    SDK. Seu usuário clica duas vezes em vez de uma; nada mais difere.

    O Instagram se comporta da mesma forma quando é vinculado **via uma Página do Facebook** — isto é, quando a
    sessão carrega `instagramLinkMethod: "facebook"`, ou quando a configuração de
    [Instagram Login](/docs/multiple-users/manage-user-profiles#instagram-login) da sua conta seleciona esse
    fluxo. Com o Instagram Login direto não há botão extra.
  </Accordion>

  <Accordion title="Bluesky e Telegram mostram conteúdo na página, não um redirecionamento">
    Nenhum dos dois envia seu usuário a um login de rede. O popup renderiza conteúdo: um formulário de
    handle e senha de app para o Bluesky, e um código a ser usado para o Telegram. Os eventos de desfecho são os
    mesmos em qualquer caso.

    O X não pertence a esse grupo. Com as suas chaves na sessão ele conclui sem pedir
    nada ao seu usuário, e sem elas é recusado — veja acima.
  </Accordion>

  <Accordion title="O Telegram conclui fora do fluxo">
    O Telegram mostra um código em vez de redirecionar para qualquer lugar, e a conexão conclui quando seu
    usuário usa esse código — depois que o popup já se foi. Não há evento de navegador a esperar, então faça polling em
    [Consultar uma Link Session](/docs/apis/profiles/get-link-session) e observe `completedNetworks`.
  </Accordion>

  <Accordion title="Facebook Groups não pode ser conectado desta forma">
    Facebook Groups não é um alvo de vinculação, então `network: "fbg"` retorna `code: 508` quando você cria
    a sessão.

    O WhatsApp **está** disponível em modo direto. Ele abre o Embedded Signup da Meta no popup, e os
    eventos de desfecho são os mesmos de qualquer outra rede.
  </Accordion>
</AccordionGroup>

<h2 id="native-apps">
  Apps nativos
</h2>

Um app nativo abre a mesma `url`, no **navegador do sistema**, e descobre o resultado fazendo polling em
[Consultar uma Link Session](/docs/apis/profiles/get-link-session). Defina `origin` como o seu esquema
personalizado (`myapp://connected`) para que a página tenha um caminho de volta para o seu app; um esquema
personalizado não pode receber eventos, porque não há janela de navegador para a qual enviá-los.

* **iOS** — `ASWebAuthenticationSession` ou `SFSafariViewController`.
* **Android** — Chrome Custom Tabs.

<Warning>
  **Nunca abra uma URL de vinculação em um webview incorporado** (`WKWebView`, `UIWebView`,
  `WebView` do Android). As redes sociais se recusam a autenticar em um deles: o Google rejeita o login com
  `disallowed_useragent`, e a Meta o bloqueia de imediato. Seu usuário vê a página de erro da própria rede,
  não a nossa, e nada que você possa mudar do seu lado corrige isso. Os componentes de navegador do sistema acima
  existem exatamente por esse motivo e mantêm o usuário dentro do seu app.
</Warning>

## O que o modo direto exige

<ul className="custom-bullets">
  <li>
    O **[Max Pack](/docs/additional/maxpack)**. Criar uma sessão em modo connect sem ele retorna
    `code: 504`, seja lá o que mais a requisição diga.
  </li>

  <li>
    Um **`origin`** em cada sessão. Não há allowlist nem etapa de registro — você o envia
    por chamada. Omiti-lo retorna `code: 505`; um valor que não é uma origem `https`, um esquema
    personalizado ou `http://localhost` retorna `code: 506`.
  </li>

  <li>
    Um **`network`** que sua conta tenha habilitado. Um nome não reconhecido retorna `code: 508`; um
    reconhecido que sua conta não habilitou retorna `code: 509`, que você pode corrigir na sua página
    [Social Networks](/docs/multiple-users/manage-user-profiles#set-social-networks-access).
  </li>

  <li>
    **Não** `allowedSocial`. Ele não pode ser combinado com `network` (`code: 507`) — uma sessão de rede
    única já é sua própria allowlist.
  </li>
</ul>

Cada um destes está na referência de
[Erros de Link Session](/docs/errors/errors-ayrshare#link-session-errors), com a mensagem que a
API retorna.

## Próximos passos

<Card title="Eventos de conclusão de vinculação" icon="tower-broadcast" href="/docs/multiple-users/link-completion-events" horizontal>
  Cada evento que o popup envia, e o listener para recebê-los.
</Card>

## Relacionados

<Card title="Criar uma Link Session" icon="link" href="/docs/apis/profiles/create-link-session#connect-mode" horizontal>
  Os parâmetros `mode`, `origin` e `network`, e os formatos de resposta.
</Card>

<Card title="Consultar uma Link Session" icon="magnifying-glass" href="/docs/apis/profiles/get-link-session" horizontal>
  Faça polling pela conclusão quando você não pode usar um popup.
</Card>
