Skip to main content

Eliminate API integration boilerplate. Define endpoints once, get intelligent client classes with full IDE support.

Project description

๐Ÿš€ Smart API Integrations

Eliminate boilerplate when integrating 3rd party APIs. Define endpoints once, get intelligent client classes with full IDE support.

Python 3.8+ License: MIT

๐ŸŽฏ The Problem

Integrating 3rd party APIs typically requires:

# โŒ Lots of boilerplate for each API call
import requests

def get_github_user(username):
    headers = {'Authorization': f'token {GITHUB_TOKEN}'}
    response = requests.get(f'https://api.github.com/users/{username}', headers=headers)
    if response.status_code != 200:
        raise Exception(f"API error: {response.status_code}")
    return response.json()

def get_github_repo(owner, repo):
    headers = {'Authorization': f'token {GITHUB_TOKEN}'}
    response = requests.get(f'https://api.github.com/repos/{owner}/{repo}', headers=headers)
    if response.status_code != 200:
        raise Exception(f"API error: {response.status_code}")
    return response.json()

# ... repeat for every endpoint

โœจ The Solution

Smart API Integrations eliminates this boilerplate:

  1. Define endpoints once in a YAML config (manually or AI-generated)
  2. Get a client class with intelligent methods
  3. Generate type stubs for full IDE support
# โœ… Zero boilerplate - just use the client
from smart_api_integrations import GithubAPIClient

github = GithubAPIClient()
user = github.get_user(username='octocat')           # Full IDE support!
repo = github.get_repo(owner='octocat', repo='Hello-World')

๐Ÿš€ Quick Start

1. Install the Package

pip install smart-api-integrations

2. Set Environment Variables

export SMART_API_INTEGRATIONS_PROVIDERS_DIR="./providers"

# Authentication tokens (provider-specific environment variables)
export GITHUB_TOKEN="your_github_token"                    # Bearer token
export STRIPE_API_KEY="sk_test_your_stripe_key"           # API key
export MYAPI_USERNAME="your_username"                      # Basic auth
export MYAPI_PASSWORD="your_password"                      # Basic auth
export MYAPI_CLIENT_ID="your_client_id"                   # OAuth2 (provider-specific)
export MYAPI_CLIENT_SECRET="your_client_secret"           # OAuth2 (provider-specific)
export MYAPI_JWT_TOKEN="your_jwt_token"                   # JWT (provider-specific)

3. Use Pre-built Providers

GitHub provider comes pre-configured as an example:

from smart_api_integrations import GithubAPIClient

# Uses GITHUB_TOKEN environment variable automatically
github = GithubAPIClient()
user = github.get_user(username='octocat')
print(f"User: {user.data['name']}")

# Or override authentication
github = GithubAPIClient(token_value='your_custom_token')

Note: GitHub is provided as a sample provider. For other APIs, follow the workflow below to add your own providers.

๐Ÿ”ง Adding New API Providers

Method 1: Manual Configuration

Create providers/myapi/config.yaml:

name: myapi
base_url: https://api.myservice.com/v1
description: My API Service
auth:
  type: bearer_token
  token_value: ${MYAPI_TOKEN}
endpoints:
  get_user:
    path: /users/{user_id}
    method: GET
    description: Get user by ID
    parameters:
      user_id: {type: string, required: true, in: path}
  list_users:
    path: /users
    method: GET
    description: List all users
    parameters:
      page: {type: integer, required: false, in: query}
      limit: {type: integer, required: false, in: query}
  create_user:
    path: /users
    method: POST
    description: Create a new user
    parameters:
      name: {type: string, required: true, in: body}
      email: {type: string, required: true, in: body}

Method 2: AI-Generated Configuration

# Generate endpoints from API documentation
smart-api-integrations add-endpoints myapi \
    --url "https://docs.myservice.com/api" \
    --max-endpoints 10

Method 3: CLI Provider Creation

smart-api-integrations add-provider \
    --name "myapi" \
    --base-url "https://api.myservice.com/v1" \
    --auth-type "bearer_token"

๐ŸŽฏ Creating Client Classes

Option 1: Use Universal Client

from smart_api_integrations import UniversalAPIClient

# Works with any configured provider
myapi = UniversalAPIClient('myapi')
user = myapi.get_user(user_id='123')
users = myapi.list_users(page=1, limit=10)
new_user = myapi.create_user(name='John', email='john@example.com')

Option 2: Create Custom Client Class

Create my_project/clients.py:

import os
from smart_api_integrations.clients.universal import UniversalAPIClient

class MyAPIClient(UniversalAPIClient):
    """Custom client for MyAPI with additional business logic."""
    
    def __init__(self, **auth_overrides):
        # Handle authentication based on your provider's auth type
        if 'token_value' not in auth_overrides:
            token = os.getenv('MYAPI_TOKEN')  # Bearer token
            if token:
                auth_overrides['token_value'] = token
        
        # For API key auth, use:
        # if 'api_key_value' not in auth_overrides:
        #     auth_overrides['api_key_value'] = os.getenv('MYAPI_KEY')
        
        super().__init__('myapi', **auth_overrides)
    
    def get_active_users(self):
        """Get only active users - custom business logic."""
        all_users = self.list_users()
        if all_users.success:
            return [user for user in all_users.data if user.get('status') == 'active']
        return []
    
    def create_user_with_validation(self, name: str, email: str):
        """Create user with email validation."""
        if '@' not in email:
            raise ValueError("Invalid email address")
        return self.create_user(name=name, email=email)

# Usage
from my_project.clients import MyAPIClient

api = MyAPIClient()  # Uses MYAPI_TOKEN automatically
active_users = api.get_active_users()
new_user = api.create_user_with_validation('John', 'john@example.com')

Option 3: Generate Dedicated Client Class

# Generate a dedicated client class file
smart-api-integrations generate-client myapi \
    --output-file "./my_project/myapi_client.py" \
    --class-name "MyAPIClient"

This creates a standalone client class:

# Auto-generated my_project/myapi_client.py
import os
from typing import Optional, Dict, Any
from smart_api_integrations.clients.universal import UniversalAPIClient
from smart_api_integrations.core.schema import APIResponse

class MyAPIClient(UniversalAPIClient):
    def __init__(self, **auth_overrides):
        """
        Initialize the myapi API client.
        
        Args:
            **auth_overrides: Authentication overrides
                            If not provided, reads from environment variables
        """
        # Set default authentication from environment if not provided
        if 'token_value' not in auth_overrides:
            token = os.getenv('MYAPI_TOKEN')
            if token:
                auth_overrides['token_value'] = token
            else:
                raise ValueError("myapi token required. Set MYAPI_TOKEN environment variable or pass token_value.")
        super().__init__('myapi', **auth_overrides)
    
    def get_user(self, user_id: str) -> APIResponse:
        """Get user by ID."""
        return self._client.call_endpoint('get_user', params={'user_id': user_id})
    
    def list_users(self, page: int = None, limit: int = None) -> APIResponse:
        """List all users."""
        params = {}
        if page is not None:
            params['page'] = page
        if limit is not None:
            params['limit'] = limit
        return self._client.call_endpoint('list_users', params=params)
    
    def create_user(self, name: str, email: str) -> APIResponse:
        """Create a new user."""
        return self._client.call_endpoint('create_user', json_data={'name': name, 'email': email})

๐Ÿ›ก๏ธ Type Safety & IDE Support

Generate Type Stubs

# Generate type stubs for full IDE support
smart-api-integrations generate-type-stubs myapi \
    --output-dir "./typings"

This creates typings/myapi.pyi:

# Auto-generated type stubs
from smart_api_integrations.core.schema import APIResponse

class MyAPIClient:
    def get_user(self, user_id: str) -> APIResponse: ...
    def list_users(self, page: int = None, limit: int = None) -> APIResponse: ...
    def create_user(self, name: str, email: str) -> APIResponse: ...

Using with Full IDE Support

from smart_api_integrations import UniversalAPIClient

myapi = UniversalAPIClient('myapi')

# IDE will show:
# - Method suggestions: get_user, list_users, create_user
# - Parameter hints: user_id (required), page (optional), etc.
# - Return type: APIResponse
user = myapi.get_user(user_id='123')  # Full autocomplete!

๐Ÿ”ง Parameter Intelligence

The framework automatically handles different parameter types:

# Path parameters (go in URL)
user = api.get_user(user_id='123')  # โ†’ GET /users/123

# Query parameters (go in URL query string)  
users = api.list_users(page=2, limit=50)  # โ†’ GET /users?page=2&limit=50

# Body parameters (go in JSON body)
new_user = api.create_user(name='John', email='john@example.com')
# โ†’ POST /users with body: {"name": "John", "email": "john@example.com"}

# Mixed parameters (automatically separated)
result = api.update_user(
    user_id='123',        # โ†’ path parameter
    name='John Smith',    # โ†’ body parameter
    notify=True          # โ†’ query parameter
)
# โ†’ PUT /users/123?notify=true with body: {"name": "John Smith"}

๐Ÿ“– Real-World Example: Stripe Integration

1. Create Configuration

# providers/stripe/config.yaml
name: stripe
base_url: https://api.stripe.com/v1
auth:
  type: bearer_token
  token_value: ${STRIPE_API_KEY}
endpoints:
  list_customers:
    path: /customers
    method: GET
    parameters:
      limit: {type: integer, required: false, in: query}
  create_customer:
    path: /customers
    method: POST
    parameters:
      email: {type: string, required: true, in: body}
      name: {type: string, required: false, in: body}
  get_customer:
    path: /customers/{customer_id}
    method: GET
    parameters:
      customer_id: {type: string, required: true, in: path}

2. Generate Type Stubs

smart-api-integrations generate-type-stubs stripe

3. Create Custom Client

# my_project/stripe_client.py
from smart_api_integrations import UniversalAPIClient

class StripeClient(UniversalAPIClient):
    def __init__(self):
        super().__init__('stripe')
    
    def find_customer_by_email(self, email: str):
        """Find customer by email address."""
        customers = self.list_customers()
        if customers.success:
            for customer in customers.data['data']:
                if customer.get('email') == email:
                    return customer
        return None
    
    def create_customer_safe(self, email: str, name: str = None):
        """Create customer only if email doesn't exist."""
        existing = self.find_customer_by_email(email)
        if existing:
            return {'exists': True, 'customer': existing}
        
        result = self.create_customer(email=email, name=name)
        return {'exists': False, 'customer': result.data if result.success else None}

4. Use with Full IDE Support

from my_project.stripe_client import StripeClient

stripe = StripeClient()

# Full autocomplete and type checking!
customers = stripe.list_customers(limit=10)
new_customer = stripe.create_customer(email='john@example.com', name='John Doe')
customer = stripe.get_customer(customer_id='cus_123')

# Custom methods
safe_result = stripe.create_customer_safe('jane@example.com', 'Jane Doe')

๐Ÿ› ๏ธ CLI Reference

Provider Management

# Add new provider
smart-api-integrations add-provider --name myapi --base-url https://api.example.com

# Generate endpoints from documentation  
smart-api-integrations add-endpoints myapi --url https://docs.example.com/api

# List all providers
smart-api-integrations list-providers

Webhook Management

# Add webhook configuration to a provider
smart-api-integrations add-webhook github --event push --secret-env GITHUB_WEBHOOK_SECRET

# Generate webhook handler class
smart-api-integrations generate-webhook-handler github --events push pull_request --output-file ./handlers/github_handler.py
# Generate a GitHub webhook handler class
from smart_api_integrations.webhooks import generate_webhook_handler, get_webhook_routes

# Generate handler class with event methods
GitHubHandler = generate_webhook_handler('github', events=['push', 'pull_request'])

# Extend with custom logic
class MyGitHubHandler(GitHubHandler):
    def on_push(self, event):
        print(f"Received push to {event.payload['repository']['name']}")
        return self.success_response({'processed': True})

# Instantiate handler
handler = MyGitHubHandler()

# Integrate with your framework
from flask import Flask
app = Flask(__name__)
app.register_blueprint(get_webhook_routes('flask'))

๐Ÿ“˜ Quick Start | ๐Ÿ” Integration Guide | โšก Integration Example

Code Generation

# Generate type stubs for IDE support
smart-api-integrations generate-type-stubs myapi

# Generate dedicated client class
smart-api-integrations generate-client myapi --output-file ./clients/myapi.py

# Test provider configuration
smart-api-integrations test myapi --endpoint get_user

๐Ÿ” Authentication Types

Smart API Integrations supports all common authentication methods with automatic environment variable handling.

Environment Variable Naming Convention

All environment variables follow the pattern {PROVIDER_NAME}_{AUTH_FIELD}:

Auth Type Environment Variables Override Parameters
Bearer Token {PROVIDER}_TOKEN token_value
API Key {PROVIDER}_API_KEY api_key_value
Basic Auth {PROVIDER}_USERNAME, {PROVIDER}_PASSWORD username, password
OAuth2 {PROVIDER}_CLIENT_ID, {PROVIDER}_CLIENT_SECRET oauth2_client_id, oauth2_client_secret
JWT {PROVIDER}_JWT_TOKEN jwt_token

Examples: GITHUB_TOKEN, STRIPE_API_KEY, MYAPI_CLIENT_ID, SALESFORCE_JWT_TOKEN

Real-World Examples

# Different providers, different auth types
export GITHUB_TOKEN="ghp_your_github_token"                    # GitHub: Bearer token
export STRIPE_API_KEY="sk_test_your_stripe_key"               # Stripe: API key
export SALESFORCE_CLIENT_ID="your_salesforce_client_id"       # Salesforce: OAuth2
export SALESFORCE_CLIENT_SECRET="your_salesforce_secret"      # Salesforce: OAuth2
export FIREBASE_JWT_TOKEN="your_firebase_jwt"                 # Firebase: JWT
export TWILIO_USERNAME="your_twilio_sid"                      # Twilio: Basic auth
export TWILIO_PASSWORD="your_twilio_auth_token"               # Twilio: Basic auth
# Each client automatically uses its provider-specific environment variables
github = GithubAPIClient()        # Uses GITHUB_TOKEN
stripe = StripeAPIClient()        # Uses STRIPE_API_KEY
salesforce = SalesforceAPIClient() # Uses SALESFORCE_CLIENT_ID + SALESFORCE_CLIENT_SECRET
firebase = FirebaseAPIClient()    # Uses FIREBASE_JWT_TOKEN
twilio = TwilioAPIClient()        # Uses TWILIO_USERNAME + TWILIO_PASSWORD

# Or override any authentication
github = GithubAPIClient(token_value='custom_token')
salesforce = SalesforceAPIClient(
    oauth2_client_id='custom_id',
    oauth2_client_secret='custom_secret'
)

Bearer Token (GitHub, OpenAI, etc.)

# Provider config
auth:
  type: bearer_token
  token_value: ${GITHUB_TOKEN}
# Environment variable
export GITHUB_TOKEN="ghp_your_github_token"
# Usage - automatically uses GITHUB_TOKEN
github = GithubAPIClient()

# Or override
github = GithubAPIClient(token_value='custom_token')

API Key in Header (Stripe, etc.)

# Provider config
auth:
  type: api_key
  key_name: Authorization
  key_value: Bearer ${STRIPE_API_KEY}
# Environment variable
export STRIPE_API_KEY="sk_test_your_stripe_key"
# Usage - automatically uses STRIPE_API_KEY
stripe = StripeAPIClient()

# Or override
stripe = StripeAPIClient(api_key_value='sk_test_custom_key')

API Key in Query (OpenWeatherMap, etc.)

# Provider config
auth:
  type: api_key
  key_name: appid
  key_value: ${OPENWEATHERMAP_API_KEY}
  location: query
# Environment variable
export OPENWEATHERMAP_API_KEY="your_api_key"

Basic Authentication

# Provider config
auth:
  type: basic
  username: ${MYAPI_USERNAME}
  password: ${MYAPI_PASSWORD}
# Environment variables
export MYAPI_USERNAME="your_username"
export MYAPI_PASSWORD="your_password"
# Usage - automatically uses environment variables
api = MyAPIClient()

# Or override
api = MyAPIClient(username='custom_user', password='custom_pass')

OAuth2 Client Credentials

# Provider config
auth:
  type: oauth2
  oauth2_client_id: ${MYAPI_CLIENT_ID}
  oauth2_client_secret: ${MYAPI_CLIENT_SECRET}
  oauth2_token_url: https://api.service.com/oauth/token
# Environment variables (provider-specific)
export MYAPI_CLIENT_ID="your_client_id"
export MYAPI_CLIENT_SECRET="your_client_secret"
# Usage - automatically uses MYAPI_CLIENT_ID and MYAPI_CLIENT_SECRET
api = MyAPIClient()

# Or override
api = MyAPIClient(
    oauth2_client_id='custom_client_id',
    oauth2_client_secret='custom_client_secret'
)

JWT Token

# Provider config
auth:
  type: jwt
  jwt_token: ${MYAPI_JWT_TOKEN}
# Environment variable (provider-specific)
export MYAPI_JWT_TOKEN="your_jwt_token"
# Usage - automatically uses MYAPI_JWT_TOKEN
api = MyAPIClient()

# Or override
api = MyAPIClient(jwt_token='custom_jwt_token')

๐Ÿ”‘ Authentication Summary

โœ… Provider-Specific: Each provider uses its own environment variables
โœ… Override Support: All auth parameters can be overridden during initialization
โœ… Multiple Auth Types: Bearer Token, API Key, Basic Auth, OAuth2, JWT
โœ… Automatic Detection: Auth type determined from provider configuration
โœ… IDE Support: Full type hints for all authentication parameters

๐Ÿ”„ Complete Workflow

Here's the complete workflow for adding a new API provider:

1. Add Provider Configuration

# Option A: Manual configuration
mkdir -p providers/myapi
cat > providers/myapi/config.yaml << EOF
name: myapi
base_url: https://api.myservice.com/v1
description: My API Service
auth:
  type: bearer_token
  token_value: \${MYAPI_TOKEN}
endpoints:
  get_user:
    path: /users/{user_id}
    method: GET
    parameters:
      user_id: {type: string, required: true, in: path}
EOF

# Option B: Use CLI to generate from docs
smart-api-integrations add-endpoints myapi --url "https://docs.myservice.com/api" --max-endpoints 10

2. Set Authentication

# Set environment variables based on auth type (provider-specific)
export MYAPI_TOKEN="your_api_token"                    # For bearer_token
# export MYAPI_API_KEY="your_key"                      # For api_key
# export MYAPI_USERNAME="user"                         # For basic auth
# export MYAPI_PASSWORD="pass"                         # For basic auth
# export MYAPI_CLIENT_ID="client_id"                   # For oauth2
# export MYAPI_CLIENT_SECRET="client_secret"           # For oauth2
# export MYAPI_JWT_TOKEN="jwt_token"                   # For jwt

3. Generate Client Class

# Generate a dedicated client class
smart-api-integrations generate-client myapi \
    --class-name "MyAPIClient" \
    --output-file "./clients/myapi_client.py"

4. Generate Type Stubs (Optional)

# Generate type stubs for IDE support
smart-api-integrations generate-type-stubs --provider myapi --output-dir "./typings"

# For the GitHub sample provider:
smart-api-integrations generate-type-stubs --provider github --output-dir "./typings"

5. Use the Client

from clients.myapi_client import MyAPIClient

# Automatically uses provider-specific environment variables
client = MyAPIClient()  # Uses MYAPI_TOKEN (or MYAPI_CLIENT_ID + MYAPI_CLIENT_SECRET for OAuth2)

# Or override authentication (works for all auth types)
client = MyAPIClient(token_value='custom_token')                    # Bearer token override
# client = MyAPIClient(api_key_value='custom_key')                 # API key override
# client = MyAPIClient(username='user', password='pass')           # Basic auth override
# client = MyAPIClient(                                            # OAuth2 override
#     oauth2_client_id='custom_id',
#     oauth2_client_secret='custom_secret'
# )
# client = MyAPIClient(jwt_token='custom_jwt')                     # JWT override

# Make API calls with full IDE support
user = client.get_user(user_id='123')
print(f"User: {user.data['name']}")

๐Ÿ“ฆ Local Development Setup

1. Install for Development

# Install the package in development mode
git clone https://github.com/yourusername/smart-api-integrations.git
cd smart-api-integrations
pip install -e .

2. Create Your Project Structure

my_project/
โ”œโ”€โ”€ providers/           # API configurations
โ”‚   โ”œโ”€โ”€ myapi/
โ”‚   โ”‚   โ””โ”€โ”€ config.yaml
โ”‚   โ””โ”€โ”€ stripe/
โ”‚       โ””โ”€โ”€ config.yaml
โ”œโ”€โ”€ clients/             # Custom client classes
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ myapi_client.py
โ”‚   โ””โ”€โ”€ stripe_client.py
โ”œโ”€โ”€ typings/             # Generated type stubs
โ”‚   โ”œโ”€โ”€ myapi.pyi
โ”‚   โ””โ”€โ”€ stripe.pyi
โ””โ”€โ”€ main.py             # Your application

3. Environment Configuration

# .env file
SMART_API_INTEGRATIONS_PROVIDERS_DIR="./providers"
GITHUB_TOKEN="your_github_token"
STRIPE_API_KEY="your_stripe_key"
MYAPI_TOKEN="your_api_token"

4. Use in Your Application

# main.py
import os
from dotenv import load_dotenv
from clients.myapi_client import MyAPIClient
from clients.stripe_client import StripeClient

load_dotenv()

# Initialize clients
myapi = MyAPIClient()
stripe = StripeClient()

# Use with full IDE support
users = myapi.list_users(limit=10)
customers = stripe.list_customers(limit=5)

๐Ÿงช Testing Your Integration

# Test your custom client
def test_myapi_integration():
    client = MyAPIClient()
    
    # Test endpoint availability
    methods = client.list_available_methods()
    assert 'get_user' in methods
    
    # Test actual API call (with real token)
    user = client.get_user(user_id='test_user')
    assert user.success
    assert 'name' in user.data

# Run tests
pytest tests/

๐ŸŽฏ Key Benefits

  • โœ… Zero Boilerplate: Define endpoints once, use everywhere
  • โœ… Type Safety: Full IDE support with generated type stubs
  • โœ… Intelligent Parameters: Automatic routing of path/query/body parameters
  • โœ… Custom Logic: Easy to extend with business-specific methods
  • โœ… Production Ready: Built-in error handling, retries, rate limiting
  • โœ… AI Assistance: Generate endpoints from documentation URLs
  • โœ… Webhook Support: Easily handle incoming webhook events
  • โœ… Framework Integration: Works with Flask, FastAPI, and Django

๐Ÿ“„ License

MIT License - see LICENSE file for details.

๐Ÿ†˜ Support


Stop writing API boilerplate. Start building features. ๐Ÿš€

pip install smart-api-integrations

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

smart_api_integrations-0.1.0.tar.gz (108.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

smart_api_integrations-0.1.0-py3-none-any.whl (82.8 kB view details)

Uploaded Python 3

File details

Details for the file smart_api_integrations-0.1.0.tar.gz.

File metadata

  • Download URL: smart_api_integrations-0.1.0.tar.gz
  • Upload date:
  • Size: 108.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for smart_api_integrations-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e548bf7a68529eb9154f1b3250b27f4f3787cf65df02545cf37f265acd38d842
MD5 e5e5758e9eba41726ca276386bffa9e6
BLAKE2b-256 96844cf717042baca6790078e9215761dd82651ae567f7f2cbeedbeb9c62327b

See more details on using hashes here.

Provenance

The following attestation bundles were made for smart_api_integrations-0.1.0.tar.gz:

Publisher: python-publish.yml on behera116/smart-api-integrations

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file smart_api_integrations-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for smart_api_integrations-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5eb63f977402414755003d8959ee89542540211e8c40e5d4b8a3195a119d998a
MD5 e0b043ae333f8b92de478960d00659de
BLAKE2b-256 864c296ed1f123bb8c5aa093da1a82eb3c22abebda817a3abb9a6a37a49ef035

See more details on using hashes here.

Provenance

The following attestation bundles were made for smart_api_integrations-0.1.0-py3-none-any.whl:

Publisher: python-publish.yml on behera116/smart-api-integrations

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page