# Developer quickstart
URL: https://metorial.com/docs/build/quickstart

Get up and running with Metorial in under 5 minutes

---

<PageIntro>
  <Learn>
    * How to install the Metorial SDK
    * Available AI providers and integrations
    * How to create sessions and use tools
    * OAuth flow for authenticated services
  </Learn>

  <Reading>
    **Before you begin**

    * [Create API keys](/docs/build/api)

    **References**

    * [GitHub: metorial-node](https://github.com/metorial/metorial-node)
    * [GitHub: metorial-python](https://github.com/metorial/metorial-python)
  </Reading>
</PageIntro>

## Prerequisites [#prerequisites]

1. **Metorial API key**: Get one from [platform.metorial.com](https://platform.metorial.com)
2. **Provider deployment ID**: Deploy a provider (e.g., Exa for search) from the dashboard
3. **AI provider API key**: OpenAI, Anthropic, Google, etc.

## Installation [#installation]

The Metorial SDK consists of two parts: the core SDK (which handles sessions and tool management) and a provider package (which integrates with your chosen AI model). Install both to get started.

<CodeBlockTabs defaultValue="TypeScript" groupId="language" mode="shell">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="TypeScript">
      TypeScript
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Python">
      Python
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="TypeScript">
    <Shell>
      <Command>
        {`# Install the core SDK
          npm install metorial

          # Install a provider package (choose one or more)
          npm install @metorial/ai-sdk      # Vercel AI SDK (recommended)
          npm install @metorial/anthropic   # Anthropic Claude
          npm install @metorial/openai      # OpenAI
          npm install @metorial/google      # Google Gemini
          npm install @metorial/mistral     # Mistral
          npm install @metorial/deepseek    # DeepSeek`}
      </Command>
    </Shell>
  </CodeBlockTab>

  <CodeBlockTab value="Python">
    <Shell>
      <Command>
        {`# Install the SDK
          pip install metorial

          # Install your AI provider
          pip install anthropic   # For Claude
          pip install openai      # For OpenAI/DeepSeek`}
      </Command>
    </Shell>
  </CodeBlockTab>
</CodeBlockTabs>

We support OpenAI, Anthropic, Google, Mistral, DeepSeek, and any OpenAI-compatible API. See the [TypeScript SDK](https://github.com/metorial/metorial-node) and [Python SDK](https://github.com/metorial/metorial-python) repos for all available providers.

## Your first AI agent [#your-first-ai-agent]

This example shows how to create an AI agent that can use tools from your deployed providers. The agent will have access to any tools provided by your provider deployment (like search, file operations, or API calls).

**What this code does:**

1. Initializes the Metorial SDK with your API key
2. Creates a session connected to your provider deployment
3. Passes the available tools to your AI model
4. Handles tool calls in an agentic loop

<CodeBlockTabs defaultValue="TypeScript" mode="code">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="TypeScript">
      TypeScript
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Python">
      Python
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="TypeScript">
    ```typescript
    import { Metorial } from 'metorial';
    import { metorialAiSdk } from '@metorial/ai-sdk';
    import { anthropic } from '@ai-sdk/anthropic';
    import { stepCountIs, streamText } from 'ai';

    let metorial = new Metorial({
        apiKey: process.env.METORIAL_API_KEY
    });

    let session = await metorial.connect({
      adapter: metorialAiSdk(),
      providers: [
        { providerDeploymentId: 'your-provider-deployment-id' }
      ]
    });

    let result = streamText({
    	model: anthropic('claude-sonnet-4-20250514'),
    	prompt: 'Search for the latest AI research',
    	stopWhen: stepCountIs(10),
    	tools: session.tools()
    });

    for await (let textPart of result.textStream) {
    	process.stdout.write(textPart);
    }
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Python">
    ```python
    from metorial import Metorial, metorial_anthropic
    from anthropic import AsyncAnthropic
    import asyncio
    import os

    metorial = Metorial(api_key=os.getenv("METORIAL_API_KEY"))
    anthropic = AsyncAnthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

    async def main():
        session = await metorial.connect(
            adapter=metorial_anthropic(),
            providers=[{"provider_deployment_id": "your-provider-deployment-id"}],
        )

        response = await anthropic.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=1024,
            tools=session.tools(),
            messages=[{"role": "user", "content": "What's trending on Hacker News?"}],
        )

        if response.stop_reason == "tool_use":
            tool_calls = [b for b in response.content if b.type == "tool_use"]
            results = await session.call_tools(tool_calls)
            # Add results to messages and continue conversation...

    asyncio.run(main())
    ```
  </CodeBlockTab>
</CodeBlockTabs>

## OAuth flow [#oauth-flow]

For services requiring user authentication (like Slack, GitHub, or Google Calendar), use a **Provider Setup Session** to authorize your users. The resulting **Provider Auth Config** stores their credentials for reuse.

**The flow:**

1. Create a Provider Setup Session for each service that needs authentication
2. Redirect your user to the session URL to complete OAuth
3. Wait for the setup session to complete — you get back an auth config
4. Pass the auth config ID when creating sessions for that user

<CodeBlockTabs defaultValue="TypeScript" mode="code">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="TypeScript">
      TypeScript
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Python">
      Python
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="TypeScript">
    ```typescript
    import { Metorial } from 'metorial';
    import { metorialAnthropic } from '@metorial/anthropic';

    let metorial = new Metorial({
        apiKey: process.env.METORIAL_API_KEY
    });

    // 1. Create a setup session for the provider
    let setupSession = await metorial.providerDeployments.setupSessions.create({
        providerId: 'your-slack-provider-id',
        providerAuthMethodId: 'oauth'
        // callbackUri: 'https://yourapp.com/oauth/callback'
    });

    // 2. Send the URL to your user
    console.log('Authorize Slack:', setupSession.url);

    // 3. Wait for completion — returns the completed setup session
    let completed = await metorial.providerDeployments.setupSessions.waitForCompletion([setupSession]);

    // Store completed[0].authConfig.id for this user in your database

    // 4. Use the auth config in a session
    let session = await metorial.connect({
      adapter: metorialAnthropic(),
      providers: [
        {
    		providerDeploymentId: 'your-provider-deployment-id',
    		providerAuthConfigId: completed[0]!.authConfig!.id
    	}
      ]
    });

    let tools = session.tools();
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Python">
    ```python
    import asyncio
    from metorial import Metorial, metorial_anthropic

    async def main():
        metorial = Metorial(api_key="your-metorial-api-key")

        # 1. Create a setup session for the provider
        setup_session = await metorial.providers.setup_sessions.create(
            provider_id="your-slack-provider-id",
            provider_auth_method_id="oauth"
            # redirect_url="https://yourapp.com/oauth/callback"
        )

        # 2. Send the URL to your user
        print(f"Authorize Slack: {setup_session.url}")

        # 3. Wait for completion — returns the completed setup session
        completed = await metorial.wait_for_setup_session([setup_session])

        # Store completed.auth_config.id for this user in your database

        # 4. Use the auth config in a session
        session = await metorial.connect(
            adapter=metorial_anthropic(),
            providers=[
                {
                    "provider_deployment_id": "your-slack-provider-deployment-id",
                    "provider_auth_config_id": completed[0].auth_config.id
                },
                {
                    "provider_deployment_id": "your-exa-deployment-id"  # No OAuth needed
                }
            ],
        )
        tools = session.tools()  # Use tools...

    asyncio.run(main())
    ```
  </CodeBlockTab>
</CodeBlockTabs>

## Error handling [#error-handling]

The Metorial SDK provides specific error types to help you handle different failure scenarios. Catch `MetorialAPIError` for API-related issues like authentication failures, rate limits, or invalid deployment IDs.

<CodeBlockTabs defaultValue="TypeScript" mode="code">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="TypeScript">
      TypeScript
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Python">
      Python
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="TypeScript">
    ```typescript
    import { MetorialAPIError } from 'metorial';

    try {
        /* ... */
    } catch (error) {
        if (error instanceof MetorialAPIError) {
            console.error(`API Error: ${error.message} (Status: ${error.status})`);
        } else {
            console.error('Unexpected error:', error);
        }
    }
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Python">
    ```python
    from metorial import AuthenticationError, NotFoundError, RateLimitError

    try:
        session = await metorial.connect(
            adapter=metorial_openai(),
            providers=[{"provider_deployment_id": "your-deployment-id"}],
        )
        tools = session.tools()
    except AuthenticationError:
        print("Check your METORIAL_API_KEY")
    except NotFoundError:
        print("Deployment not found - verify your deployment ID")
    except RateLimitError:
        print("Rate limited - try again later")
    except Exception as e:
        print(f"Unexpected error: {e}")
    ```
  </CodeBlockTab>
</CodeBlockTabs>