While the consume() method inherently validates a User API Key before attempting a charge, we recommend validating the API Key proactively before processing incoming requests. There are two places where you might choose to do so:
  • (Recommended) Immediately after User API Key extraction (e.g. in middleware).
  • Inside your MCP Server feature handlers, before processing the core business logic.
This guide assumes that you have already successfully extracted the User API Key from the HTTP request. To learn more about that, please refer to our Extracting API Keys guide.

The validate_api_key() Method

This method checks the status of a given User API Key with the AgentPay system.

Parameters:

  • api_key (str): Required. The User API Key to be validated.

Returns:

The validate_api_key() method returns a ValidationResult object with the following attributes:
  • is_valid (bool): True if the API key is valid, active, and recognized by AgentPay. False otherwise.
  • invalid_reason (str | None): If is_valid is False, provides the reason for invalidity. Possible values:
    • "invalid_key": The key is not recognized or has been revoked/deactivated
    • "outstanding_payment": The key is associated with an account that has an unpaid consumption attempt from a previous failed consume() call due to insufficient funds. The key will be automatically reactivated once the user adds sufficient funds to their account.
    • "insufficient_balance": The key is valid but the associated account has no remaining balance (including free credits)
    • None if is_valid is True
The "outstanding_payment" state is a temporary condition that occurs when a user attempts to consume more than their available balance. Once they add sufficient funds to their account, the outstanding payment will be automatically processed and their API key will be reactivated.

Example Usage

from agentpay_sdk import AgentPayClient
from mcp.server.fastmcp import FastMCP
from contextvars import ContextVar

# Initialize AgentPay client
agentpay_client = AgentPayClient(service_token="YOUR_SERVICE_TOKEN")

# Create FastMCP instance
mcp = FastMCP("your-server-name")

# Define context variable for API key
api_key_context: ContextVar[str | None] = ContextVar("api_key_context", default=None)

# Middleware to extract and validate API Key
class ApiKeyMiddleware(BaseHTTPMiddleware):
    async def dispatch(
        self, request: Request, call_next: RequestResponseEndpoint
    ) -> Response:
        api_key = request.headers.get("X-AGENTPAY-API-KEY")

        # Validate User API key if present (recommended placement)
        if api_key:
            try:
                validation_result = agentpay_client.validate_api_key(api_key=api_key)
                if not validation_result.is_valid:
                    return JSONResponse(
                        {"error": "Unauthorized", "message": f"Invalid API Key: {validation_result.invalid_reason}"},
                        status_code=401
                    )
            except Exception as e:
                return JSONResponse(
                    {"error": "Internal Server Error", "message": "API Key validation failed"},
                    status_code=500
                )

        # Set context var for use in route handlers
        token = api_key_context.set(api_key)
        try:
            response = await call_next(request)
        finally:
            api_key_context.reset(token)
        return response

# Example MCP tool using FastMCP decorator
@mcp.tool()
async def example_tool(param1: str) -> str:
    """Example tool that demonstrates API key usage.
    
    Args:
        param1: Example parameter
    """
    # Get API key from context
    user_api_key = api_key_context.get()
    
    if user_api_key is None:
        return "Error: API Key missing"
    
    # Now you have the user_api_key (which was validated earlier by our middleware), you can use it to consume usage.
    # For example:
    # COST_CENTS = 10
    # usage_id = str(uuid.uuid4())
    # consume_result = agentpay_client.consume(
    #     api_key=user_api_key,
    #     amount_cents=COST_CENTS,
    #     usage_event_id=usage_id
    # )
    # if not consume_result.success:
    #     return f"Error: {consume_result.error_message}"
    
    return f"Tool executed with parameter: {param1}"

When to Use validate_api_key() vs. consume()

  • consume(): Use this when you are performing a billable action. It implicitly validates the key as part of the consumption process. If the key is invalid, consume() will fail.
  • validate_api_key(): Use this for pre-checks if needed:
    • If you want to provide a distinct user experience for invalid keys versus insufficient funds (though consume() also returns error codes for this).
    • Before performing non-billable but sensitive or resource-intensive setup operations.
    • Avoid excessive calls: Don’t call validate_api_key() and then immediately consume() for every request if not strictly necessary, as this involves two separate calls to the AgentPay system. Rely on consume() for validation if an operation is definitely billable.

Next Steps