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

# Email Magic Links overview

Email Magic Links are a secure passwordless authentication option that create a low-friction login experience for users.

When a user logs in via an Email Magic Link, Stytch generates a unique, one-time-use token embedded in a URL and sends it to the user's email address. The user authenticates their identity by successfully receiving and clicking on this link before the link expires, at which point Stytch will either issue a Session or prompt the user to perform MFA if they are enrolled.

## Implement Email Magic Links

<Tabs>
  <Tab title="Discovery flow" icon="compass">
    The Discovery flow is designed for centralized login pages where users authenticate before selecting which Organization to access.

    <Steps>
      <Step title="Send the Magic Link">
        Send a magic link to the user's email address:

        ```bash theme={null}
        curl --request POST \
          --url https://test.stytch.com/v1/b2b/magic_links/email/discovery/send \
          --header 'Content-Type: application/json' \
          --user 'PROJECT_ID:SECRET' \
          --data '{
            "email_address": "user@example.com",
            "discovery_redirect_url": "https://yourapp.com/authenticate"
          }'
        ```

        **Parameters:**

        * `email_address`: The user's email address
        * `discovery_redirect_url`: Where to redirect after clicking the magic link

        **Response:**

        ```json theme={null}
        {
          "status_code": 200,
          "request_id": "request-id-test-...",
          "intermediate_session_token": "DOYoip3rvIMMW5lgItikFK-Ak1CfMsgjuiCyI7uuU94="
        }
        ```
      </Step>

      <Step title="Authenticate the Magic Link">
        When the user clicks the link, they'll be redirected to your `discovery_redirect_url` with a `token` query parameter. Exchange this token for session information:

        ```bash theme={null}
        curl --request POST \
          --url https://test.stytch.com/v1/b2b/magic_links/authenticate \
          --header 'Content-Type: application/json' \
          --user 'PROJECT_ID:SECRET' \
          --data '{
            "magic_links_token": "TOKEN_FROM_QUERY_PARAM"
          }'
        ```

        **Response:**

        ```json theme={null}
        {
          "status_code": 200,
          "request_id": "request-id-test-...",
          "member_id": "member-test-...",
          "intermediate_session_token": "DOYoip3rvIMMW5lgItikFK...",
          "email_address": "user@example.com",
          "discovered_organizations": [
            {
              "organization": {
                "organization_id": "organization-test-...",
                "organization_name": "Acme Corp",
                "organization_slug": "acme-corp"
              },
              "membership": {
                "type": "eligible_to_join_by_email_domain",
                "details": {}
              }
            }
          ]
        }
        ```
      </Step>

      <Step title="Exchange the intermediate session">
        After the user selects an organization, exchange the intermediate session token for a full session:

        ```bash theme={null}
        curl --request POST \
          --url https://test.stytch.com/v1/b2b/discovery/intermediate_sessions/exchange \
          --header 'Content-Type: application/json' \
          --user 'PROJECT_ID:SECRET' \
          --data '{
            "intermediate_session_token": "DOYoip3rvIMMW5lgItikFK...",
            "organization_id": "organization-test-...",
            "session_duration_minutes": 60
          }'
        ```

        **Response:**

        ```json theme={null}
        {
          "status_code": 200,
          "request_id": "request-id-test-...",
          "member_id": "member-test-...",
          "session_token": "WJtR5BCy38Szd5AfoDpf0iqFKEt4EE5JhdpRWT...",
          "session_jwt": "eyJhbGc...",
          "member": { /* member object */ },
          "organization": { /* organization object */ },
          "session": { /* session object */ }
        }
        ```
      </Step>
    </Steps>

    <Note>
      The Discovery flow returns an `intermediate_session_token` which must be exchanged for a full session after the user selects their organization.
    </Note>
  </Tab>

  <Tab title="Organization flow" icon="building">
    The Organization flow is for organization-specific login pages where the organization to log into is already known (e.g., `acme.yourapp.com`).

    <Steps>
      <Step title="Send the Magic Link">
        Send a magic link for a specific organization:

        ```bash theme={null}
        curl --request POST \
          --url https://test.stytch.com/v1/b2b/magic_links/email/login_or_signup \
          --header 'Content-Type: application/json' \
          --user 'PROJECT_ID:SECRET' \
          --data '{
            "organization_id": "organization-test-...",
            "email_address": "user@example.com",
            "login_redirect_url": "https://acme.yourapp.com/authenticate",
            "signup_redirect_url": "https://acme.yourapp.com/authenticate"
          }'
        ```

        **Parameters:**

        * `organization_id`: The organization's ID
        * `email_address`: The user's email address
        * `login_redirect_url`: Where to redirect existing users after clicking
        * `signup_redirect_url`: Where to redirect new users after clicking

        **Response:**

        ```json theme={null}
        {
          "status_code": 200,
          "request_id": "request-id-test-...",
          "member_id": "member-test-...",
          "member_created": false
        }
        ```
      </Step>

      <Step title="Authenticate the Magic Link">
        When the user clicks the link, they'll be redirected with a `token` query parameter. Authenticate the token:

        ```bash theme={null}
        curl --request POST \
          --url https://test.stytch.com/v1/b2b/magic_links/authenticate \
          --header 'Content-Type: application/json' \
          --user 'PROJECT_ID:SECRET' \
          --data '{
            "magic_links_token": "TOKEN_FROM_QUERY_PARAM",
            "session_duration_minutes": 60
          }'
        ```

        **Response:**

        ```json theme={null}
        {
          "status_code": 200,
          "request_id": "request-id-test-...",
          "member_id": "member-test-...",
          "organization_id": "organization-test-...",
          "session_token": "WJtR5BCy38Szd5AfoDpf0iqFKEt4EE5JhdpRWT...",
          "session_jwt": "eyJhbGc...",
          "member": { /* member object */ },
          "organization": { /* organization object */ },
          "session": { /* session object */ },
          "method_id": "email-test-..."
        }
        ```
      </Step>

      <Step title="Use the session">
        Store the `session_token` or `session_jwt` to authenticate future API requests. You can validate sessions using the [session authenticate endpoint](/docs/api-reference/b2b/api/sessions/authenticate-session).
      </Step>
    </Steps>
  </Tab>
</Tabs>

## Next steps

<CardGroup cols={2}>
  <Card title="Sessions" icon="clock" href="/docs/multi-tenant-auth/manage-sessions">
    Learn about session management
  </Card>

  <Card title="Organizations" icon="building" href="/docs/multi-tenant-auth/data-model">
    Understand the B2B data model
  </Card>
</CardGroup>
