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

# Query Agents

> Learn how users can query AI Agents after purchasing access

Once a user (or agent) purchases a Payment Plan, if this Plan has some AI Agents or Services attached to it, the user can query these AI Agents or Services.

For identifying the user as a valid subscriber, they need to include a valid **Access Token** in their requests. This is sent using the standard **HTTP Authorization header**.

## Integration Methods

Nevermined offers two main approaches for integrating with AI agents:

### No-Code Integration (Proxy-Based)

For **quick setup with no backend changes**, use Nevermined Proxy instances:

<Info>
  Nevermined Proxy instances are **standard HTTP Proxies** that automatically handle **user authorization** and **payment validation** for your AI Agents or Services.
</Info>

* **Zero code changes** to your existing AI agent
* **Automatic payment validation** before requests reach your service
* **Built-in rate limiting** and usage tracking
* **Standard HTTP proxy** - works with any HTTP-based service

### Low-Code Integration (Direct)

For **maximum control and customization**, integrate directly with your agent code:

* **Custom payment validation logic** in your application
* **Fine-grained control** over request processing
* **Custom error handling** and user experience
* **Direct integration** with the Payments library

Once a user is a subscriber, sending a request is simple with either approach.

## Get the AI Agent or Service Access Token

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const credentials = await payments.agents.getAgentAccessToken(planId, agentId)
    // OUTPUT: credentials:
    // {
    //   accessToken: 'eJyNj0sKgDAURP9lJQ ....',
    //   proxies: [ 'https://proxy.nevermined.app' ]
    // }  
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # Get agent access token for the given plan and agent
    credentials = payments.agents.get_agent_access_token(plan_id, agent_id)
    # OUTPUT: credentials:
    # {
    #   "accessToken": "eJyNj0sKgDAURP9lJQ ....",
    #   "proxies": [ "https://proxy.nevermined.app" ]
    # }
    ```
  </Tab>
</Tabs>

## Sending a query to the AI Agent

If the response of the `getAgentAccessToken` method contains a valid `accessToken`, the user can query the AI Agent making a standard HTTP request.
This request must be sent directly to the Agent (the description of the Agent API is in the Agent Metadata) or if the `agentAccessParams` includes an entry in the `proxies` array, through one of the Nevermined Proxy instances listed in the `proxies` array of the response.

<Info>
  Because Nevermined authorizes standard HTTP requests, they can be used to protect any kind of AI Agent or Service exposing an HTTP API.
</Info>

### Using cURL

```bash theme={null}
export AGENT_ACCESS_TOKEN="eJyNj0sKgDAURP9lJQ..."

curl -k -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AGENT_ACCESS_TOKEN" \
  -d '{"query": "hey there"}' \
  https://my.agent.io/prompt
```

### Using Programming Languages

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const agentHTTPOptions = {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
        Authorization: `Bearer ${credentials.accessToken}`,
      },
      body: JSON.stringify({
        query: "What's the weather like today?",
        parameters: {
          location: "New York"
        }
      })
    }

    const response = await fetch(new URL('https://my.agent.io/prompt'), agentHTTPOptions)
    const result = await response.json()
    console.log('Agent response:', result)
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    # HTTP options for the agent request
    headers = {
        "Accept": "application/json",
        "Content-Type": "application/json",
        "Authorization": f"Bearer {credentials['accessToken']}",
    }

    payload = {
        "query": "What's the weather like today?",
        "parameters": {
            "location": "New York"
        }
    }

    response = requests.post(
        "https://my.agent.io/prompt", 
        headers=headers, 
        json=payload
    )

    if response.status_code == 200:
        result = response.json()
        print('Agent response:', result)
    else:
        print(f'Error: {response.status_code} - {response.text}')
    ```
  </Tab>
</Tabs>

## Complete Query Flow Example

Here's a complete example showing the full flow from getting access tokens to querying an agent:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    async function queryAIAgent(planId: string, agentId: string, query: string) {
      try {
        // Step 1: Get access credentials
        const credentials = await payments.agents.getAgentAccessToken(planId, agentId)
        
        if (!credentials.accessToken) {
          throw new Error('No access token received - check if plan is valid and has balance')
        }
        
        // Step 2: Get agent details
        const agent = await payments.agents.getAgent(agentId)
        const endpoint = agent.endpoints[0] // Use first endpoint
        
        // Step 3: Make the request
        const response = await fetch(endpoint.url, {
          method: endpoint.method || 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${credentials.accessToken}`
          },
          body: JSON.stringify({ query })
        })
        
        if (response.status === 402) {
          throw new Error('Payment required - insufficient credits or plan expired')
        }
        
        if (!response.ok) {
          throw new Error(`Agent request failed: ${response.status} ${response.statusText}`)
        }
        
        const result = await response.json()
        
        // Step 4: Check remaining balance (optional)
        const balance = await payments.plans.getPlanBalance(planId)
        console.log(`Remaining credits: ${balance.balance}`)
        
        return result
        
      } catch (error) {
        console.error('Query failed:', error.message)
        throw error
      }
    }

    // Usage
    const result = await queryAIAgent(planId, agentId, "Explain quantum computing")
    console.log('AI Response:', result)
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests
    import json

    def query_ai_agent(plan_id, agent_id, query):
        try:
            # Step 1: Get access credentials
            credentials = payments.agents.get_agent_access_token(plan_id, agent_id)
            
            if not credentials.get('accessToken'):
                raise Exception('No access token received - check if plan is valid and has balance')
            
            # Step 2: Get agent details
            agent = payments.agents.get_agent(agent_id)
            endpoint = agent['endpoints'][0]  # Use first endpoint
            
            # Step 3: Make the request
            headers = {
                'Content-Type': 'application/json',
                'Authorization': f"Bearer {credentials['accessToken']}"
            }
            
            payload = {'query': query}
            
            response = requests.post(
                endpoint['url'],
                headers=headers,
                json=payload
            )
            
            if response.status_code == 402:
                raise Exception('Payment required - insufficient credits or plan expired')
            
            response.raise_for_status()
            result = response.json()
            
            # Step 4: Check remaining balance (optional)
            balance = payments.get_plan_balance(plan_id)
            print(f"Remaining credits: {balance.get('balance')}")
            
            return result
            
        except Exception as error:
            print(f'Query failed: {error}')
            raise error

    # Usage
    result = query_ai_agent(plan_id, agent_id, "Explain quantum computing")
    print('AI Response:', result)
    ```
  </Tab>
</Tabs>

## Handling Different Response Types

AI agents can return various types of responses. Here's how to handle them:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    async function handleAgentResponse(response: Response) {
      const contentType = response.headers.get('content-type')
      
      if (contentType?.includes('application/json')) {
        // JSON response (most common)
        return await response.json()
      } else if (contentType?.includes('text/')) {
        // Text response
        return await response.text()
      } else if (contentType?.includes('image/')) {
        // Image response
        const blob = await response.blob()
        return URL.createObjectURL(blob)
      } else {
        // Binary or other response
        return await response.arrayBuffer()
      }
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    def handle_agent_response(response):
        content_type = response.headers.get('content-type', '')
        
        if 'application/json' in content_type:
            # JSON response (most common)
            return response.json()
        elif 'text/' in content_type:
            # Text response
            return response.text
        elif 'image/' in content_type:
            # Image response
            return response.content
        else:
            # Binary or other response
            return response.content
    ```
  </Tab>
</Tabs>

## Error Handling and Status Codes

<AccordionGroup>
  <Accordion title="200 - Success">
    Request was successful and credits were deducted from the user's balance
  </Accordion>

  <Accordion title="401 - Unauthorized">
    Invalid or missing access token. User needs to get a new token
  </Accordion>

  <Accordion title="402 - Payment Required">
    User doesn't have sufficient credits or their plan has expired
  </Accordion>

  <Accordion title="403 - Forbidden">
    User has access but the specific endpoint is not allowed for their plan
  </Accordion>

  <Accordion title="429 - Rate Limited">
    Too many requests. User should wait before trying again
  </Accordion>

  <Accordion title="500 - Server Error">
    Agent internal error. This doesn't consume credits
  </Accordion>
</AccordionGroup>

## Best Practices

<CardGroup cols={2}>
  <Card title="Token Management" icon="key">
    * Cache access tokens (they're valid for a limited time)
    * Refresh tokens when they expire
    * Never expose tokens in client-side logs
  </Card>

  <Card title="Error Handling" icon="shield">
    * Always check response status codes
    * Implement retry logic for network failures
    * Handle 402 responses by prompting for plan renewal
  </Card>

  <Card title="Performance" icon="gauge">
    * Reuse access tokens across multiple requests
    * Implement request timeouts
    * Use appropriate HTTP methods (GET, POST)
  </Card>

  <Card title="Monitoring" icon="chart-line">
    * Track credit usage patterns
    * Monitor response times and error rates
    * Set up alerts for low credit balances
  </Card>
</CardGroup>

## Advanced Usage Patterns

### Batch Requests

For efficiency, you can send multiple queries in a single request:

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const batchQuery = {
      requests: [
        { id: '1', query: 'What is AI?' },
        { id: '2', query: 'Explain machine learning' },
        { id: '3', query: 'Define neural networks' }
      ]
    }

    const response = await fetch(agentEndpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${accessToken}`
      },
      body: JSON.stringify(batchQuery)
    })
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    batch_query = {
        'requests': [
            {'id': '1', 'query': 'What is AI?'},
            {'id': '2', 'query': 'Explain machine learning'},
            {'id': '3', 'query': 'Define neural networks'}
        ]
    }

    response = requests.post(
        agent_endpoint,
        headers={'Authorization': f'Bearer {access_token}'},
        json=batch_query
    )
    ```
  </Tab>
</Tabs>

### Streaming Responses

For long-running AI operations, you might want to handle streaming responses:

```typescript theme={null}
const response = await fetch(agentEndpoint, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${accessToken}`,
    'Accept': 'text/event-stream'
  },
  body: JSON.stringify({ query, stream: true })
})

const reader = response.body?.getReader()
if (reader) {
  while (true) {
    const { done, value } = await reader.read()
    if (done) break
    
    const chunk = new TextDecoder().decode(value)
    console.log('Streaming chunk:', chunk)
  }
}
```

## Next Steps

Now that you know how to query AI agents, learn how to:

<CardGroup cols={2}>
  <Card title="Build AI Agents" icon="robot" href="/integration-guide/process-requests">
    Learn how to create AI agents that accept paid requests
  </Card>

  <Card title="Monitor Usage" icon="chart-line" href="/introduction/troubleshooting">
    Track and optimize your AI service usage
  </Card>
</CardGroup>
