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

# Register Provider Then Login

> Handle provider_not_registered by registering once, then calling login again for suki_token

**Problem:** Login returns `401` with `provider_not_registered` for a new provider.

**Solution:** Call [Register](/api-reference/authentication/register) once (`201` or `409` both OK for this flow), then call [Login](/api-reference/authentication/login) again and use the returned `suki_token` as `sdp_suki_token`.

<Note>
  This cookbook assumes you already have your Partner ID and Partner Token. For Bearer partners, also send `provider_id` on register and login.
</Note>

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    async function login(partnerId: string, partnerToken: string, providerId?: string) {
      const body: Record<string, string> = {
        partner_id: partnerId,
        partner_token: partnerToken,
      };
      if (providerId) body.provider_id = providerId;

      const res = await fetch("https://sdp.suki.ai/api/v1/auth/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        throw new Error(String(data.message || res.status));
      }
      return data.suki_token as string;
    }

    async function registerProvider(input: {
      partnerId: string;
      partnerToken: string;
      providerName: string;
      providerOrgId: string;
      providerId?: string;
    }) {
      const body: Record<string, string> = {
        partner_id: input.partnerId,
        partner_token: input.partnerToken,
        provider_name: input.providerName,
        provider_org_id: input.providerOrgId,
      };
      if (input.providerId) body.provider_id = input.providerId;

      const res = await fetch("https://sdp.suki.ai/api/v1/auth/register", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });
      // New link: 201. Already linked: 409. Both are success for this flow.
      if (res.status !== 201 && res.status !== 409) {
        throw new Error(`Register failed: ${res.status}`);
      }
    }

    async function loginWithRegisterFallback(
      partnerId: string,
      partnerToken: string,
      providerId: string | undefined,
      providerName: string,
      providerOrgId: string
    ) {
      try {
        return await login(partnerId, partnerToken, providerId);
      } catch (err) {
        if (!String(err).includes("provider_not_registered")) throw err;
        await registerProvider({
          partnerId,
          partnerToken,
          providerName,
          providerOrgId,
          providerId,
        });
        return login(partnerId, partnerToken, providerId);
      }
    }

    const sukiToken = await loginWithRegisterFallback(
      partnerId,
      partnerToken,
      providerId,
      "Dr. Jane Smith",
      "org-123"
    );
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={"theme":{"light":"github-dark","dark":"material-theme-darker"}}
    from typing import Optional

    import requests

    def login(partner_id: str, partner_token: str, provider_id: Optional[str] = None) -> str:
        payload = {"partner_id": partner_id, "partner_token": partner_token}
        if provider_id:
            payload["provider_id"] = provider_id
        r = requests.post(
            "https://sdp.suki.ai/api/v1/auth/login",
            headers={"Content-Type": "application/json"},
            json=payload,
        )
        if not r.ok:
            raise RuntimeError(r.json().get("message", r.text))
        return r.json()["suki_token"]

    def register_provider(
        partner_id: str,
        partner_token: str,
        provider_name: str,
        provider_org_id: str,
        provider_id: Optional[str] = None,
    ) -> None:
        payload = {
            "partner_id": partner_id,
            "partner_token": partner_token,
            "provider_name": provider_name,
            "provider_org_id": provider_org_id,
        }
        if provider_id:
            payload["provider_id"] = provider_id
        r = requests.post(
            "https://sdp.suki.ai/api/v1/auth/register",
            headers={"Content-Type": "application/json"},
            json=payload,
        )
        # New link: 201. Already linked: 409. Both are success for this flow.
        if r.status_code not in (201, 409):
            r.raise_for_status()

    def login_with_register_fallback(
        partner_id: str,
        partner_token: str,
        provider_id: Optional[str],
        provider_name: str,
        provider_org_id: str,
    ) -> str:
        try:
            return login(partner_id, partner_token, provider_id)
        except RuntimeError as err:
            if "provider_not_registered" not in str(err):
                raise
            register_provider(
                partner_id, partner_token, provider_name, provider_org_id, provider_id
            )
            return login(partner_id, partner_token, provider_id)

    suki_token = login_with_register_fallback(
        partner_id,
        partner_token,
        provider_id,
        "Dr. Jane Smith",
        "org-123",
    )
    ```
  </Tab>
</Tabs>

## Common mistakes

* Treat register `409` as failure. For this flow, the provider is already linked.
* Forget Bearer `provider_id` on both register and login when you are a Bearer partner.

## Other cookbooks

<div className="cookbook-hub-wrap">
  <div className="hp-io-method-grid tut-hub-card-grid" data-cookbook-related-grid>
    <a className="hp-io-method-card tut-hub-method-card" href="/documentation/cookbooks/bearer-provider-id-on-login">
      <div className="tut-hub-card-media tut-hub-card-media--blue" aria-hidden="true" />

      <div className="hp-io-method-card-body">
        <div className="tut-hub-card-badges">
          <span className="hp-wn-badge hp-wn-badge-new">Authentication</span>
          <span className="hp-wn-badge cookbook-hub-badge-surface cookbook-hub-badge-surface--api">API</span>
        </div>

        <h3 className="hp-io-method-card-title">Add provider\_id to Bearer Login</h3>

        <p className="hp-io-method-card-desc cookbook-hub-card-desc">
          Send provider\_id on Bearer login.
        </p>

        <div className="hp-io-method-card-meta tut-hub-card-foot" aria-label="5 min">
          <div className="tut-hub-card-foot-meta">
            <span className="hp-io-method-card-meta-time">5 min</span>
          </div>
        </div>
      </div>
    </a>

    <a className="hp-io-method-card tut-hub-method-card" href="/documentation/cookbooks/pass-emr-encounter-id">
      <div className="tut-hub-card-media" aria-hidden="true" />

      <div className="hp-io-method-card-body">
        <div className="tut-hub-card-badges">
          <span className="hp-wn-badge hp-wn-badge-new">Ambient</span>
          <span className="hp-wn-badge cookbook-hub-badge-surface cookbook-hub-badge-surface--api">API</span>
        </div>

        <h3 className="hp-io-method-card-title">Share One Note Across Products</h3>

        <p className="hp-io-method-card-desc cookbook-hub-card-desc">
          Create session with emr\_encounter\_id.
        </p>

        <div className="hp-io-method-card-meta tut-hub-card-foot" aria-label="5 min">
          <div className="tut-hub-card-foot-meta">
            <span className="hp-io-method-card-meta-time">5 min</span>
          </div>
        </div>
      </div>
    </a>
  </div>
</div>
