RequestRocket Documentation
Guides

Integrating RequestRocket into Your SaaS

Learn how to use RequestRocket to power integrations in your SaaS application

Integrating RequestRocket into Your SaaS

Learn how to use RequestRocket as the integration layer for your SaaS application, enabling your customers to connect with third-party platforms securely and reliably.

Why Use RequestRocket for Your SaaS?

RequestRocket simplifies complex integration scenarios by:

  • Managing Authentication: Handle complex OAuth, API keys, and custom auth for each customer
  • Isolating Customer Data: Each customer gets their own credentials and proxies
  • Centralizing Management: Programmatically manage all customer integrations via the Core API
  • Ensuring Security: Credentials are encrypted and never exposed to your application
  • Enabling Self-Service: Give customers API keys to manage their own integrations

Integration Patterns

Pattern 1: Managed Integrations

Your SaaS manages all integrations for customers, storing their third-party credentials securely.

Use Cases:

  • Integration marketplace
  • Pre-built connectors
  • Managed data sync

Pattern 2: Customer Self-Service

Customers use API keys you provide to make their own requests through RequestRocket.

Use Cases:

  • Developer platforms
  • API-as-a-Service
  • White-label solutions

Pattern 3: Multi-Tenant Isolation

Create separate RequestRocket clients for each of your customers.

Use Cases:

  • Enterprise customers
  • Compliance requirements
  • Complete isolation

Implementation Guide

Set Up Your RequestRocket Infrastructure

Create your main SaaS client:

# Create your main SaaS client
curl -X POST "https://api.requestrocket.com/clients" \
  -H "Authorization: $REQUESTROCKET_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clientName": "MySaaS Integration Manager"
  }'

# Response will include:
# {
#   "clientId": "cli_abc123...",
#   "clientName": "MySaaS Integration Manager",
#   ...
# }
// Initialize your SaaS's RequestRocket client
const RR_USER_TOKEN = process.env.REQUESTROCKET_USER_TOKEN;

async function initializeSaaS() {
  // Create your main client
  const response = await fetch('https://api.requestrocket.com/clients', {
    method: 'POST',
    headers: {
      'Authorization': RR_USER_TOKEN,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      clientName: 'MySaaS Integration Manager'
    })
  });
  
  const client = await response.json();
  console.log('SaaS Client ID:', client.clientId);
  
  return client;
}
import requests
import os

RR_USER_TOKEN = os.getenv('REQUESTROCKET_USER_TOKEN')

def initialize_saas():
    """Initialize your SaaS's RequestRocket client"""
    response = requests.post(
        'https://api.requestrocket.com/clients',
        headers={
            'Authorization': RR_USER_TOKEN,
            'Content-Type': 'application/json'
        },
        json={
            'clientName': 'MySaaS Integration Manager'
        }
    )
    
    client = response.json()
    print(f'SaaS Client ID: {client["clientId"]}')
    
    return client
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

type Client struct {
    ClientID   string `json:"clientId"`
    ClientName string `json:"clientName"`
}

func initializeSaaS() (*Client, error) {
    rrToken := os.Getenv("REQUESTROCKET_USER_TOKEN")
    
    payload := map[string]string{
        "clientName": "MySaaS Integration Manager",
    }
    
    jsonData, err := json.Marshal(payload)
    if err != nil {
        return nil, err
    }
    
    req, err := http.NewRequest(
        "POST",
        "https://api.requestrocket.com/clients",
        bytes.NewBuffer(jsonData),
    )
    if err != nil {
        return nil, err
    }
    
    req.Header.Set("Authorization", rrToken)
    req.Header.Set("Content-Type", "application/json")
    
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    
    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }
    
    var result Client
    if err := json.Unmarshal(body, &result); err != nil {
        return nil, err
    }
    
    fmt.Printf("SaaS Client ID: %s\n", result.ClientID)
    return &result, nil
}
import okhttp3.*;
import com.google.gson.Gson;
import java.io.IOException;

public class SaaSInitializer {
    private static final String RR_USER_TOKEN = System.getenv("REQUESTROCKET_USER_TOKEN");
    private static final OkHttpClient httpClient = new OkHttpClient();
    private static final Gson gson = new Gson();
    
    public static class Client {
        public String clientId;
        public String clientName;
    }
    
    public static Client initializeSaaS() throws IOException {
        // Create request payload
        String json = gson.toJson(new Object() {
            final String clientName = "MySaaS Integration Manager";
        });
        
        RequestBody body = RequestBody.create(
            json,
            MediaType.parse("application/json")
        );
        
        Request request = new Request.Builder()
            .url("https://api.requestrocket.com/clients")
            .header("Authorization", RR_USER_TOKEN)
            .header("Content-Type", "application/json")
            .post(body)
            .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Request failed: " + response);
            }
            
            Client client = gson.fromJson(
                response.body().string(),
                Client.class
            );
            
            System.out.println("SaaS Client ID: " + client.clientId);
            return client;
        }
    }
}

Create Integration for a New Customer

When a customer connects a third-party service:

# 1. Create proxy credential for your customer
curl -X POST "https://api.requestrocket.com/clients/$SAAS_CLIENT_ID/credentials" \
  -H "Authorization: $RR_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "credentialName": "customer123-proxy-salesforce",
    "credentialType": "proxy",
    "authType": "apiKey",
    "region": "us-east-1",
    "secret": {
      "keyName": "X-API-Key",
      "keyValue": "generated-secure-key"
    }
  }'

# 2. Create target credential (customer's third-party creds)
curl -X POST "https://api.requestrocket.com/clients/$SAAS_CLIENT_ID/credentials" \
  -H "Authorization: $RR_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "credentialName": "customer123-salesforce-target",
    "credentialType": "target",
    "authType": "oauth2",
    "region": "us-east-1",
    "secret": {
      "accessToken": "customer-oauth-token",
      "refreshToken": "customer-refresh-token"
    }
  }'

# 3. Get or create target
curl -X GET "https://api.requestrocket.com/clients/$SAAS_CLIENT_ID/targets?targetName=Salesforce" \
  -H "Authorization: $RR_USER_TOKEN"

# 4. Create proxy
curl -X POST "https://api.requestrocket.com/clients/$SAAS_CLIENT_ID/proxies" \
  -H "Authorization: $RR_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "proxyName": "customer123-salesforce",
    "region": "us-east-1",
    "proxyCredentialId": "crd_proxy123",
    "targetId": "tgt_sf123",
    "targetCredentialId": "crd_target123",
    "active": true
  }'

# Store the returned proxy details in your database
async function createCustomerIntegration(customerId, integration) {
  const { platform, credentials } = integration;
  
  // 1. Create proxy credential for your customer
  const proxyCred = await fetch(
    `https://api.requestrocket.com/clients/${SAAS_CLIENT_ID}/credentials`,
    {
      method: 'POST',
      headers: {
        'Authorization': RR_USER_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        credentialName: `${customerId}-proxy-${platform}`,
        credentialType: 'proxy',
        authType: 'apiKey',
        region: 'us-east-1',
        secret: {
          keyName: 'X-API-Key',
          keyValue: generateSecureKey() // Generate unique key for customer
        }
      })
    }
  ).then(r => r.json());
  
  // 2. Create target credential (customer's third-party creds)
  const targetCred = await fetch(
    `https://api.requestrocket.com/clients/${SAAS_CLIENT_ID}/credentials`,
    {
      method: 'POST',
      headers: {
        'Authorization': RR_USER_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        credentialName: `${customerId}-${platform}-target`,
        credentialType: 'target',
        authType: credentials.type, // e.g., 'oauth2', 'apiKey'
        region: 'us-east-1',
        secret: credentials.secret
      })
    }
  ).then(r => r.json());
  
  // 3. Create or get target
  const target = await ensureTarget(platform);
  
  // 4. Create proxy
  const proxy = await fetch(
    `https://api.requestrocket.com/clients/${SAAS_CLIENT_ID}/proxies`,
    {
      method: 'POST',
      headers: {
        'Authorization': RR_USER_TOKEN,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        proxyName: `${customerId}-${platform}`,
        region: 'us-east-1',
        proxyCredentialId: proxyCred.credentialId,
        targetId: target.targetId,
        targetCredentialId: targetCred.credentialId,
        active: true
      })
    }
  ).then(r => r.json());
  
  // 5. Store mapping in your database
  await db.integrations.create({
    customerId,
    platform,
    proxyId: proxy.proxyId,
    proxyCredentialId: proxyCred.credentialId,
    proxyUrl: proxy.baseURL,
    customerApiKey: proxyCred.secret.keyValue
  });
  
  return {
    proxyUrl: proxy.baseURL,
    apiKey: proxyCred.secret.keyValue
  };
}
def create_customer_integration(customer_id, integration):
    """Create integration for a new customer"""
    platform = integration['platform']
    credentials = integration['credentials']
    
    # 1. Create proxy credential for your customer
    proxy_cred_response = requests.post(
        f'https://api.requestrocket.com/clients/{SAAS_CLIENT_ID}/credentials',
        headers={
            'Authorization': RR_USER_TOKEN,
            'Content-Type': 'application/json'
        },
        json={
            'credentialName': f'{customer_id}-proxy-{platform}',
            'credentialType': 'proxy',
            'authType': 'apiKey',
            'region': 'us-east-1',
            'secret': {
                'keyName': 'X-API-Key',
                'keyValue': generate_secure_key()  # Generate unique key
            }
        }
    )
    proxy_cred = proxy_cred_response.json()
    
    # 2. Create target credential (customer's third-party creds)
    target_cred_response = requests.post(
        f'https://api.requestrocket.com/clients/{SAAS_CLIENT_ID}/credentials',
        headers={
            'Authorization': RR_USER_TOKEN,
            'Content-Type': 'application/json'
        },
        json={
            'credentialName': f'{customer_id}-{platform}-target',
            'credentialType': 'target',
            'authType': credentials['type'],
            'region': 'us-east-1',
            'secret': credentials['secret']
        }
    )
    target_cred = target_cred_response.json()
    
    # 3. Create or get target
    target = ensure_target(platform)
    
    # 4. Create proxy
    proxy_response = requests.post(
        f'https://api.requestrocket.com/clients/{SAAS_CLIENT_ID}/proxies',
        headers={
            'Authorization': RR_USER_TOKEN,
            'Content-Type': 'application/json'
        },
        json={
            'proxyName': f'{customer_id}-{platform}',
            'region': 'us-east-1',
            'proxyCredentialId': proxy_cred['credentialId'],
            'targetId': target['targetId'],
            'targetCredentialId': target_cred['credentialId'],
            'active': True
        }
    )
    proxy = proxy_response.json()
    
    # 5. Store mapping in your database
    db.integrations.create({
        'customerId': customer_id,
        'platform': platform,
        'proxyId': proxy['proxyId'],
        'proxyCredentialId': proxy_cred['credentialId'],
        'proxyUrl': proxy['baseURL'],
        'customerApiKey': proxy_cred['secret']['keyValue']
    })
    
    return {
        'proxyUrl': proxy['baseURL'],
        'apiKey': proxy_cred['secret']['keyValue']
    }
type Integration struct {
    Platform    string                 `json:"platform"`
    Credentials map[string]interface{} `json:"credentials"`
}

type IntegrationResult struct {
    ProxyURL string `json:"proxyUrl"`
    APIKey   string `json:"apiKey"`
}

func createCustomerIntegration(customerID string, integration Integration) (*IntegrationResult, error) {
    // 1. Create proxy credential
    proxyCredPayload := map[string]interface{}{
        "credentialName": fmt.Sprintf("%s-proxy-%s", customerID, integration.Platform),
        "credentialType": "proxy",
        "authType":       "apiKey",
        "region":         "us-east-1",
        "secret": map[string]string{
            "keyName":  "X-API-Key",
            "keyValue": generateSecureKey(),
        },
    }
    
    proxyCred, err := createCredential(SAAS_CLIENT_ID, proxyCredPayload)
    if err != nil {
        return nil, err
    }
    
    // 2. Create target credential
    targetCredPayload := map[string]interface{}{
        "credentialName": fmt.Sprintf("%s-%s-target", customerID, integration.Platform),
        "credentialType": "target",
        "authType":       integration.Credentials["type"],
        "region":         "us-east-1",
        "secret":         integration.Credentials["secret"],
    }
    
    targetCred, err := createCredential(SAAS_CLIENT_ID, targetCredPayload)
    if err != nil {
        return nil, err
    }
    
    // 3. Create or get target
    target, err := ensureTarget(integration.Platform)
    if err != nil {
        return nil, err
    }
    
    // 4. Create proxy
    proxyPayload := map[string]interface{}{
        "proxyName":          fmt.Sprintf("%s-%s", customerID, integration.Platform),
        "region":             "us-east-1",
        "proxyCredentialId":  proxyCred["credentialId"],
        "targetId":           target["targetId"],
        "targetCredentialId": targetCred["credentialId"],
        "active":             true,
    }
    
    proxy, err := createProxy(SAAS_CLIENT_ID, proxyPayload)
    if err != nil {
        return nil, err
    }
    
    // 5. Store mapping in database
    err = db.Integrations.Create(map[string]interface{}{
        "customerId":        customerID,
        "platform":          integration.Platform,
        "proxyId":           proxy["proxyId"],
        "proxyCredentialId": proxyCred["credentialId"],
        "proxyUrl":          proxy["baseURL"],
        "customerApiKey":    proxyCred["secret"].(map[string]interface{})["keyValue"],
    })
    
    if err != nil {
        return nil, err
    }
    
    return &IntegrationResult{
        ProxyURL: proxy["baseURL"].(string),
        APIKey:   proxyCred["secret"].(map[string]interface{})["keyValue"].(string),
    }, nil
}
public class IntegrationResult {
    public String proxyUrl;
    public String apiKey;
}

public IntegrationResult createCustomerIntegration(
    String customerId, 
    Map<String, Object> integration
) throws IOException {
    String platform = (String) integration.get("platform");
    Map<String, Object> credentials = (Map<String, Object>) integration.get("credentials");
    
    // 1. Create proxy credential
    Map<String, Object> proxyCredPayload = new HashMap<>();
    proxyCredPayload.put("credentialName", customerId + "-proxy-" + platform);
    proxyCredPayload.put("credentialType", "proxy");
    proxyCredPayload.put("authType", "apiKey");
    proxyCredPayload.put("region", "us-east-1");
    
    Map<String, String> proxySecret = new HashMap<>();
    proxySecret.put("keyName", "X-API-Key");
    proxySecret.put("keyValue", generateSecureKey());
    proxyCredPayload.put("secret", proxySecret);
    
    Map<String, Object> proxyCred = createCredential(SAAS_CLIENT_ID, proxyCredPayload);
    
    // 2. Create target credential
    Map<String, Object> targetCredPayload = new HashMap<>();
    targetCredPayload.put("credentialName", customerId + "-" + platform + "-target");
    targetCredPayload.put("credentialType", "target");
    targetCredPayload.put("authType", credentials.get("type"));
    targetCredPayload.put("region", "us-east-1");
    targetCredPayload.put("secret", credentials.get("secret"));
    
    Map<String, Object> targetCred = createCredential(SAAS_CLIENT_ID, targetCredPayload);
    
    // 3. Create or get target
    Map<String, Object> target = ensureTarget(platform);
    
    // 4. Create proxy
    Map<String, Object> proxyPayload = new HashMap<>();
    proxyPayload.put("proxyName", customerId + "-" + platform);
    proxyPayload.put("region", "us-east-1");
    proxyPayload.put("proxyCredentialId", proxyCred.get("credentialId"));
    proxyPayload.put("targetId", target.get("targetId"));
    proxyPayload.put("targetCredentialId", targetCred.get("credentialId"));
    proxyPayload.put("active", true);
    
    Map<String, Object> proxy = createProxy(SAAS_CLIENT_ID, proxyPayload);
    
    // 5. Store mapping in database
    Map<String, Object> dbRecord = new HashMap<>();
    dbRecord.put("customerId", customerId);
    dbRecord.put("platform", platform);
    dbRecord.put("proxyId", proxy.get("proxyId"));
    dbRecord.put("proxyCredentialId", proxyCred.get("credentialId"));
    dbRecord.put("proxyUrl", proxy.get("baseURL"));
    
    Map<String, String> secret = (Map<String, String>) proxyCred.get("secret");
    dbRecord.put("customerApiKey", secret.get("keyValue"));
    
    db.integrations.create(dbRecord);
    
    IntegrationResult result = new IntegrationResult();
    result.proxyUrl = (String) proxy.get("baseURL");
    result.apiKey = secret.get("keyValue");
    
    return result;
}

Make Requests on Behalf of Customers

When your SaaS needs to sync data or perform operations:

# Make request through customer's proxy
# Get the customer's proxy URL and API key from your database
curl -X GET "https://us-east-1.requestrocket.com/api/prx_customer123/api/customers" \
  -H "Authorization: Bearer customer-proxy-api-key" \
  -H "Content-Type: application/json"

# POST request example
curl -X POST "https://us-east-1.requestrocket.com/api/prx_customer123/api/orders" \
  -H "Authorization: Bearer customer-proxy-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "productId": "prod_123",
    "quantity": 5
  }'
async function syncCustomerData(customerId, platform) {
  // Get customer's integration
  const integration = await db.integrations.findOne({
    customerId,
    platform
  });
  
  // Make request through their proxy
  const response = await fetch(
    `${integration.proxyUrl}/api/customers`,
    {
      headers: {
        'Authorization': `Bearer ${integration.customerApiKey}`,
        'Content-Type': 'application/json'
      }
    }
  );
  
  const data = await response.json();
  
  // Process and store data
  await processCustomerData(customerId, platform, data);
  
  return data;
}
def sync_customer_data(customer_id, platform):
    """Sync data for a specific customer"""
    # Get customer's integration
    integration = db.integrations.find_one({
        'customerId': customer_id,
        'platform': platform
    })
    
    # Make request through their proxy
    response = requests.get(
        f"{integration['proxyUrl']}/api/customers",
        headers={
            'Authorization': f"Bearer {integration['customerApiKey']}",
            'Content-Type': 'application/json'
        }
    )
    
    data = response.json()
    
    # Process and store data
    process_customer_data(customer_id, platform, data)
    
    return data
func syncCustomerData(customerID, platform string) (interface{}, error) {
    // Get customer's integration
    integration, err := db.Integrations.FindOne(map[string]interface{}{
        "customerId": customerID,
        "platform":   platform,
    })
    if err != nil {
        return nil, err
    }
    
    // Make request through their proxy
    req, err := http.NewRequest(
        "GET",
        integration["proxyUrl"].(string)+"/api/customers",
        nil,
    )
    if err != nil {
        return nil, err
    }
    
    req.Header.Set("Authorization", "Bearer "+integration["customerApiKey"].(string))
    req.Header.Set("Content-Type", "application/json")
    
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    
    var data interface{}
    if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
        return nil, err
    }
    
    // Process and store data
    if err := processCustomerData(customerID, platform, data); err != nil {
        return nil, err
    }
    
    return data, nil
}
public Object syncCustomerData(String customerId, String platform) throws IOException {
    // Get customer's integration
    Map<String, Object> integration = db.integrations.findOne(
        Map.of("customerId", customerId, "platform", platform)
    );
    
    // Make request through their proxy
    String url = integration.get("proxyUrl") + "/api/customers";
    
    Request request = new Request.Builder()
        .url(url)
        .header("Authorization", "Bearer " + integration.get("customerApiKey"))
        .header("Content-Type", "application/json")
        .get()
        .build();
    
    try (Response response = httpClient.newCall(request).execute()) {
        if (!response.isSuccessful()) {
            throw new IOException("Request failed: " + response);
        }
        
        String json = response.body().string();
        Object data = gson.fromJson(json, Object.class);
        
        // Process and store data
        processCustomerData(customerId, platform, data);
        
        return data;
    }
}

Enable Customer Self-Service

Let customers make their own API calls:

// Provide customers with their integration details
app.get('/api/integrations/:platform', authenticateCustomer, async (req, res) => {
  const { customerId } = req.user;
  const { platform } = req.params;
  
  const integration = await db.integrations.findOne({
    customerId,
    platform
  });
  
  if (!integration) {
    return res.status(404).json({ error: 'Integration not found' });
  }
  
  res.json({
    platform,
    proxyUrl: integration.proxyUrl,
    apiKey: integration.customerApiKey, // Give them the key
    documentation: `/docs/integrations/${platform}`
  });
});

Customers can then use your proxy directly:

// Customer's code
const response = await fetch(
  'https://us-east-1.requestrocket.com/api/prx_abc/orders',
  {
    headers: {
      'Authorization': 'Bearer customer-api-key-from-your-saas',
      'Content-Type': 'application/json'
    }
  }
);

Advanced Patterns

Multi-Client Architecture

For enterprise customers or compliance requirements, create separate RequestRocket clients:

# Create dedicated RequestRocket client for enterprise customer
curl -X POST "https://api.requestrocket.com/clients" \
  -H "Authorization: $RR_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clientName": "Enterprise: Acme Corp"
  }'

# Response includes the new clientId:
# {
#   "clientId": "cli_enterprise123",
#   "clientName": "Enterprise: Acme Corp",
#   ...
# }

# Now create integrations under their dedicated client
# All subsequent credential/proxy creation uses their cli_enterprise123
curl -X POST "https://api.requestrocket.com/clients/cli_enterprise123/credentials" \
  -H "Authorization: $RR_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "credentialName": "acme-salesforce-proxy",
    "credentialType": "proxy",
    ...
  }'
async function provisionEnterpriseCustomer(customerId, customerName) {
  // Create dedicated RequestRocket client for this customer
  const client = await fetch('https://api.requestrocket.com/clients', {
    method: 'POST',
    headers: {
      'Authorization': RR_USER_TOKEN,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      clientName: `Enterprise: ${customerName}`
    })
  }).then(r => r.json());
  
  // Store mapping
  await db.customers.update(customerId, {
    rrClientId: client.clientId,
    tier: 'enterprise'
  });
  
  return client;
}

// Now create all their integrations under their own client
async function createEnterpriseIntegration(customerId, platform, credentials) {
  const customer = await db.customers.findById(customerId);
  const clientId = customer.rrClientId; // Their dedicated client
  
  // Create credentials and proxies under their client
  // ... (same as before but using their clientId)
}
def provision_enterprise_customer(customer_id, customer_name):
    """Create dedicated RequestRocket client for enterprise customer"""
    # Create dedicated client
    response = requests.post(
        'https://api.requestrocket.com/clients',
        headers={
            'Authorization': RR_USER_TOKEN,
            'Content-Type': 'application/json'
        },
        json={
            'clientName': f'Enterprise: {customer_name}'
        }
    )
    
    client = response.json()
    
    # Store mapping
    db.customers.update(customer_id, {
        'rrClientId': client['clientId'],
        'tier': 'enterprise'
    })
    
    return client

def create_enterprise_integration(customer_id, platform, credentials):
    """Create integration under customer's dedicated client"""
    customer = db.customers.find_by_id(customer_id)
    client_id = customer['rrClientId']  # Their dedicated client
    
    # Create credentials and proxies under their client
    # ... (same as before but using their client_id)
func provisionEnterpriseCustomer(customerID, customerName string) (*Client, error) {
    // Create dedicated RequestRocket client
    payload := map[string]string{
        "clientName": fmt.Sprintf("Enterprise: %s", customerName),
    }
    
    jsonData, err := json.Marshal(payload)
    if err != nil {
        return nil, err
    }
    
    req, err := http.NewRequest(
        "POST",
        "https://api.requestrocket.com/clients",
        bytes.NewBuffer(jsonData),
    )
    if err != nil {
        return nil, err
    }
    
    req.Header.Set("Authorization", RR_USER_TOKEN)
    req.Header.Set("Content-Type", "application/json")
    
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    
    var client Client
    if err := json.NewDecoder(resp.Body).Decode(&client); err != nil {
        return nil, err
    }
    
    // Store mapping
    err = db.Customers.Update(customerID, map[string]interface{}{
        "rrClientId": client.ClientID,
        "tier":       "enterprise",
    })
    
    return &client, err
}

func createEnterpriseIntegration(customerID, platform string, credentials map[string]interface{}) error {
    customer, err := db.Customers.FindByID(customerID)
    if err != nil {
        return err
    }
    
    clientID := customer["rrClientId"].(string) // Their dedicated client
    
    // Create credentials and proxies under their client
    // ... (same as before but using their clientID)
    return nil
}
public Client provisionEnterpriseCustomer(String customerId, String customerName) 
    throws IOException {
    // Create dedicated RequestRocket client
    Map<String, String> payload = new HashMap<>();
    payload.put("clientName", "Enterprise: " + customerName);
    
    String json = gson.toJson(payload);
    RequestBody body = RequestBody.create(
        json, 
        MediaType.parse("application/json")
    );
    
    Request request = new Request.Builder()
        .url("https://api.requestrocket.com/clients")
        .header("Authorization", RR_USER_TOKEN)
        .header("Content-Type", "application/json")
        .post(body)
        .build();
    
    try (Response response = httpClient.newCall(request).execute()) {
        String responseJson = response.body().string();
        Client client = gson.fromJson(responseJson, Client.class);
        
        // Store mapping
        Map<String, Object> updates = new HashMap<>();
        updates.put("rrClientId", client.clientId);
        updates.put("tier", "enterprise");
        db.customers.update(customerId, updates);
        
        return client;
    }
}

public void createEnterpriseIntegration(
    String customerId, 
    String platform, 
    Map<String, Object> credentials
) throws IOException {
    Map<String, Object> customer = db.customers.findById(customerId);
    String clientId = (String) customer.get("rrClientId"); // Their dedicated client
    
    // Create credentials and proxies under their client
    // ... (same as before but using their clientId)
}

Authorization Rules per Customer

Apply different access rules for different customers:

# Apply rate limit rule for basic tier customer
curl -X POST "https://api.requestrocket.com/clients/$SAAS_CLIENT_ID/proxies/$PROXY_ID/rules" \
  -H "Authorization: $RR_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "effect": "deny",
    "priority": 900,
    "notes": "Basic tier rate limit - max 100 req/hour"
  }'

# Restrict specific endpoint for customer
curl -X POST "https://api.requestrocket.com/clients/$SAAS_CLIENT_ID/proxies/$PROXY_ID/rules" \
  -H "Authorization: $RR_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "effect": "deny",
    "priority": 800,
    "pathPattern": "/admin/*",
    "pathPresence": "present",
    "notes": "Admin endpoints restricted for customer123"
  }'

# Allow only specific HTTP methods
curl -X POST "https://api.requestrocket.com/clients/$SAAS_CLIENT_ID/proxies/$PROXY_ID/rules" \
  -H "Authorization: $RR_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "effect": "deny",
    "priority": 850,
    "methodPattern": "DELETE|PUT",
    "methodPresence": "present",
    "notes": "Read-only access - deny modifications"
  }'
async function applyCustomerRules(customerId, proxyId, ruleConfig) {
  const rules = [];
  
  // Example: Rate limit per customer tier
  if (ruleConfig.tier === 'basic') {
    rules.push({
      effect: 'deny',
      priority: 900,
      notes: 'Basic tier rate limit',
      // Add custom rate limiting logic
    });
  }
  
  // Example: Restrict certain endpoints
  if (ruleConfig.restrictedPaths) {
    for (const path of ruleConfig.restrictedPaths) {
      rules.push({
        effect: 'deny',
        priority: 800,
        pathPattern: path,
        pathPresence: 'present',
        notes: `Restricted path for ${customerId}`
      });
    }
  }
  
  // Create rules
  for (const rule of rules) {
    await fetch(
      `https://api.requestrocket.com/clients/${SAAS_CLIENT_ID}/proxies/${proxyId}/rules`,
      {
        method: 'POST',
        headers: {
          'Authorization': RR_USER_TOKEN,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(rule)
      }
    );
  }
}
def apply_customer_rules(customer_id, proxy_id, rule_config):
    """Apply authorization rules based on customer tier and config"""
    rules = []
    
    # Example: Rate limit per customer tier
    if rule_config.get('tier') == 'basic':
        rules.append({
            'effect': 'deny',
            'priority': 900,
            'notes': 'Basic tier rate limit'
        })
    
    # Example: Restrict certain endpoints
    if rule_config.get('restrictedPaths'):
        for path in rule_config['restrictedPaths']:
            rules.append({
                'effect': 'deny',
                'priority': 800,
                'pathPattern': path,
                'pathPresence': 'present',
                'notes': f'Restricted path for {customer_id}'
            })
    
    # Example: Method restrictions (read-only)
    if rule_config.get('readOnly'):
        rules.append({
            'effect': 'deny',
            'priority': 850,
            'methodPattern': 'DELETE|PUT|PATCH',
            'methodPresence': 'present',
            'notes': f'Read-only access for {customer_id}'
        })
    
    # Create rules
    for rule in rules:
        response = requests.post(
            f'https://api.requestrocket.com/clients/{SAAS_CLIENT_ID}/proxies/{proxy_id}/rules',
            headers={
                'Authorization': RR_USER_TOKEN,
                'Content-Type': 'application/json'
            },
            json=rule
        )
        response.raise_for_status()
func applyCustomerRules(customerID, proxyID string, ruleConfig map[string]interface{}) error {
    rules := []map[string]interface{}{}
    
    // Example: Rate limit per customer tier
    if tier, ok := ruleConfig["tier"].(string); ok && tier == "basic" {
        rules = append(rules, map[string]interface{}{
            "effect":   "deny",
            "priority": 900,
            "notes":    "Basic tier rate limit",
        })
    }
    
    // Example: Restrict certain endpoints
    if restrictedPaths, ok := ruleConfig["restrictedPaths"].([]string); ok {
        for _, path := range restrictedPaths {
            rules = append(rules, map[string]interface{}{
                "effect":       "deny",
                "priority":     800,
                "pathPattern":  path,
                "pathPresence": "present",
                "notes":        fmt.Sprintf("Restricted path for %s", customerID),
            })
        }
    }
    
    // Example: Method restrictions (read-only)
    if readOnly, ok := ruleConfig["readOnly"].(bool); ok && readOnly {
        rules = append(rules, map[string]interface{}{
            "effect":         "deny",
            "priority":       850,
            "methodPattern":  "DELETE|PUT|PATCH",
            "methodPresence": "present",
            "notes":          fmt.Sprintf("Read-only access for %s", customerID),
        })
    }
    
    // Create rules
    for _, rule := range rules {
        jsonData, err := json.Marshal(rule)
        if err != nil {
            return err
        }
        
        url := fmt.Sprintf(
            "https://api.requestrocket.com/clients/%s/proxies/%s/rules",
            SAAS_CLIENT_ID,
            proxyID,
        )
        
        req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
        if err != nil {
            return err
        }
        
        req.Header.Set("Authorization", RR_USER_TOKEN)
        req.Header.Set("Content-Type", "application/json")
        
        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            return err
        }
        resp.Body.Close()
        
        if resp.StatusCode >= 400 {
            return fmt.Errorf("failed to create rule: %d", resp.StatusCode)
        }
    }
    
    return nil
}
public void applyCustomerRules(
    String customerId, 
    String proxyId, 
    Map<String, Object> ruleConfig
) throws IOException {
    List<Map<String, Object>> rules = new ArrayList<>();
    
    // Example: Rate limit per customer tier
    if ("basic".equals(ruleConfig.get("tier"))) {
        Map<String, Object> rule = new HashMap<>();
        rule.put("effect", "deny");
        rule.put("priority", 900);
        rule.put("notes", "Basic tier rate limit");
        rules.add(rule);
    }
    
    // Example: Restrict certain endpoints
    if (ruleConfig.containsKey("restrictedPaths")) {
        List<String> restrictedPaths = (List<String>) ruleConfig.get("restrictedPaths");
        for (String path : restrictedPaths) {
            Map<String, Object> rule = new HashMap<>();
            rule.put("effect", "deny");
            rule.put("priority", 800);
            rule.put("pathPattern", path);
            rule.put("pathPresence", "present");
            rule.put("notes", "Restricted path for " + customerId);
            rules.add(rule);
        }
    }
    
    // Example: Method restrictions (read-only)
    if (Boolean.TRUE.equals(ruleConfig.get("readOnly"))) {
        Map<String, Object> rule = new HashMap<>();
        rule.put("effect", "deny");
        rule.put("priority", 850);
        rule.put("methodPattern", "DELETE|PUT|PATCH");
        rule.put("methodPresence", "present");
        rule.put("notes", "Read-only access for " + customerId);
        rules.add(rule);
    }
    
    // Create rules
    String url = String.format(
        "https://api.requestrocket.com/clients/%s/proxies/%s/rules",
        SAAS_CLIENT_ID,
        proxyId
    );
    
    for (Map<String, Object> rule : rules) {
        String json = gson.toJson(rule);
        RequestBody body = RequestBody.create(
            json, 
            MediaType.parse("application/json")
        );
        
        Request request = new Request.Builder()
            .url(url)
            .header("Authorization", RR_USER_TOKEN)
            .header("Content-Type", "application/json")
            .post(body)
            .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Failed to create rule: " + response.code());
            }
        }
    }
}

Webhook Forwarding

Use Async API for reliable webhook delivery:

# Forward webhook using async endpoint
# Replace /api/ with /async/ in the proxy URL
curl -X POST "https://us-east-1.requestrocket.com/async/prx_customer123/webhooks" \
  -H "Authorization: Bearer customer-proxy-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "order.created",
    "orderId": "ord_123",
    "timestamp": "2026-01-24T10:30:00Z",
    "data": {
      "amount": 99.99,
      "currency": "USD"
    }
  }'

# Response includes requestId for tracking:
# {
#   "requestId": "req_abc123xyz",
#   "status": "queued"
# }

# Check webhook delivery status
curl -X GET "https://api.requestrocket.com/clients/$SAAS_CLIENT_ID/requests/req_abc123xyz" \
  -H "Authorization: $RR_USER_TOKEN"
async function forwardWebhook(customerId, platform, webhookData) {
  const integration = await db.integrations.findOne({
    customerId,
    platform
  });
  
  // Use async endpoint for reliability
  const asyncUrl = integration.proxyUrl.replace('/api/', '/async/');
  
  const response = await fetch(`${asyncUrl}/webhooks`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${integration.customerApiKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(webhookData)
  });
  
  const { requestId } = await response.json();
  
  // Track webhook delivery
  await db.webhooks.create({
    customerId,
    platform,
    requestId,
    status: 'queued',
    payload: webhookData
  });
  
  return requestId;
}
def forward_webhook(customer_id, platform, webhook_data):
    """Forward webhook using async API for reliability"""
    integration = db.integrations.find_one({
        'customerId': customer_id,
        'platform': platform
    })
    
    # Use async endpoint for reliability
    async_url = integration['proxyUrl'].replace('/api/', '/async/')
    
    response = requests.post(
        f"{async_url}/webhooks",
        headers={
            'Authorization': f"Bearer {integration['customerApiKey']}",
            'Content-Type': 'application/json'
        },
        json=webhook_data
    )
    
    result = response.json()
    request_id = result['requestId']
    
    # Track webhook delivery
    db.webhooks.create({
        'customerId': customer_id,
        'platform': platform,
        'requestId': request_id,
        'status': 'queued',
        'payload': webhook_data
    })
    
    return request_id
func forwardWebhook(customerID, platform string, webhookData map[string]interface{}) (string, error) {
    // Get integration
    integration, err := db.Integrations.FindOne(map[string]interface{}{
        "customerId": customerID,
        "platform":   platform,
    })
    if err != nil {
        return "", err
    }
    
    // Use async endpoint for reliability
    proxyURL := integration["proxyUrl"].(string)
    asyncURL := strings.Replace(proxyURL, "/api/", "/async/", 1)
    
    // Marshal webhook data
    jsonData, err := json.Marshal(webhookData)
    if err != nil {
        return "", err
    }
    
    // Send to async endpoint
    req, err := http.NewRequest(
        "POST",
        asyncURL+"/webhooks",
        bytes.NewBuffer(jsonData),
    )
    if err != nil {
        return "", err
    }
    
    req.Header.Set("Authorization", "Bearer "+integration["customerApiKey"].(string))
    req.Header.Set("Content-Type", "application/json")
    
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    
    var result struct {
        RequestID string `json:"requestId"`
    }
    if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
        return "", err
    }
    
    // Track webhook delivery
    err = db.Webhooks.Create(map[string]interface{}{
        "customerId": customerID,
        "platform":   platform,
        "requestId":  result.RequestID,
        "status":     "queued",
        "payload":    webhookData,
    })
    
    return result.RequestID, err
}
public String forwardWebhook(
    String customerId, 
    String platform, 
    Map<String, Object> webhookData
) throws IOException {
    // Get integration
    Map<String, Object> integration = db.integrations.findOne(
        Map.of("customerId", customerId, "platform", platform)
    );
    
    // Use async endpoint for reliability
    String proxyUrl = (String) integration.get("proxyUrl");
    String asyncUrl = proxyUrl.replace("/api/", "/async/");
    
    // Send to async endpoint
    String json = gson.toJson(webhookData);
    RequestBody body = RequestBody.create(
        json, 
        MediaType.parse("application/json")
    );
    
    Request request = new Request.Builder()
        .url(asyncUrl + "/webhooks")
        .header("Authorization", "Bearer " + integration.get("customerApiKey"))
        .header("Content-Type", "application/json")
        .post(body)
        .build();
    
    try (Response response = httpClient.newCall(request).execute()) {
        String responseJson = response.body().string();
        JsonObject result = gson.fromJson(responseJson, JsonObject.class);
        String requestId = result.get("requestId").getAsString();
        
        // Track webhook delivery
        Map<String, Object> webhookRecord = new HashMap<>();
        webhookRecord.put("customerId", customerId);
        webhookRecord.put("platform", platform);
        webhookRecord.put("requestId", requestId);
        webhookRecord.put("status", "queued");
        webhookRecord.put("payload", webhookData);
        
        db.webhooks.create(webhookRecord);
        
        return requestId;
    }
}

Monitoring Customer Usage

Track usage across all customer integrations:

# Get request logs for a specific proxy
curl -X GET "https://api.requestrocket.com/clients/$SAAS_CLIENT_ID/requests?proxyId=prx_customer123&startDate=2026-01-01&endDate=2026-01-31" \
  -H "Authorization: $RR_USER_TOKEN"

# Response includes detailed request logs:
# {
#   "data": [
#     {
#       "requestId": "req_abc123",
#       "status": "completed",
#       "duration": 234,
#       "timestamp": "2026-01-24T10:30:00Z",
#       ...
#     }
#   ]
# }

# Get aggregated stats for all customer integrations
# (Requires iterating through each customer's proxies)
for proxy_id in $(get_customer_proxy_ids); do
  curl -X GET "https://api.requestrocket.com/clients/$SAAS_CLIENT_ID/requests?proxyId=$proxy_id&startDate=$START_DATE&endDate=$END_DATE" \
    -H "Authorization: $RR_USER_TOKEN"
done
async function getCustomerUsageStats(customerId, startDate, endDate) {
  const integrations = await db.integrations.find({ customerId });
  
  const stats = await Promise.all(
    integrations.map(async (integration) => {
      const response = await fetch(
        `https://api.requestrocket.com/clients/${SAAS_CLIENT_ID}/requests?` +
        `proxyId=${integration.proxyId}&startDate=${startDate}&endDate=${endDate}`,
        {
          headers: { 'Authorization': RR_USER_TOKEN }
        }
      );
      
      const { data } = await response.json();
      
      return {
        platform: integration.platform,
        totalRequests: data.length,
        successful: data.filter(r => r.status === 'completed').length,
        failed: data.filter(r => r.status === 'failed').length,
        avgDuration: data.reduce((sum, r) => sum + r.duration, 0) / data.length
      };
    })
  );
  
  return {
    customerId,
    period: { startDate, endDate },
    integrations: stats,
    total: stats.reduce((sum, s) => sum + s.totalRequests, 0)
  };
}
def get_customer_usage_stats(customer_id, start_date, end_date):
    """Track usage across all customer integrations"""
    integrations = db.integrations.find({'customerId': customer_id})
    
    stats = []
    for integration in integrations:
        response = requests.get(
            f"https://api.requestrocket.com/clients/{SAAS_CLIENT_ID}/requests",
            params={
                'proxyId': integration['proxyId'],
                'startDate': start_date,
                'endDate': end_date
            },
            headers={'Authorization': RR_USER_TOKEN}
        )
        
        data = response.json()['data']
        
        total_requests = len(data)
        successful = len([r for r in data if r['status'] == 'completed'])
        failed = len([r for r in data if r['status'] == 'failed'])
        avg_duration = sum(r['duration'] for r in data) / total_requests if total_requests > 0 else 0
        
        stats.append({
            'platform': integration['platform'],
            'totalRequests': total_requests,
            'successful': successful,
            'failed': failed,
            'avgDuration': avg_duration
        })
    
    return {
        'customerId': customer_id,
        'period': {'startDate': start_date, 'endDate': end_date},
        'integrations': stats,
        'total': sum(s['totalRequests'] for s in stats)
    }
type UsageStats struct {
    Platform      string  `json:"platform"`
    TotalRequests int     `json:"totalRequests"`
    Successful    int     `json:"successful"`
    Failed        int     `json:"failed"`
    AvgDuration   float64 `json:"avgDuration"`
}

type CustomerUsage struct {
    CustomerID   string                 `json:"customerId"`
    Period       map[string]string      `json:"period"`
    Integrations []UsageStats           `json:"integrations"`
    Total        int                    `json:"total"`
}

func getCustomerUsageStats(customerID, startDate, endDate string) (*CustomerUsage, error) {
    integrations, err := db.Integrations.Find(map[string]interface{}{
        "customerId": customerID,
    })
    if err != nil {
        return nil, err
    }
    
    stats := []UsageStats{}
    totalRequests := 0
    
    for _, integration := range integrations {
        url := fmt.Sprintf(
            "https://api.requestrocket.com/clients/%s/requests?proxyId=%s&startDate=%s&endDate=%s",
            SAAS_CLIENT_ID,
            integration["proxyId"],
            startDate,
            endDate,
        )
        
        req, _ := http.NewRequest("GET", url, nil)
        req.Header.Set("Authorization", RR_USER_TOKEN)
        
        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            return nil, err
        }
        defer resp.Body.Close()
        
        var result struct {
            Data []struct {
                Status   string  `json:"status"`
                Duration float64 `json:"duration"`
            } `json:"data"`
        }
        
        json.NewDecoder(resp.Body).Decode(&result)
        
        successful := 0
        failed := 0
        var totalDuration float64
        
        for _, r := range result.Data {
            if r.Status == "completed" {
                successful++
            } else if r.Status == "failed" {
                failed++
            }
            totalDuration += r.Duration
        }
        
        avgDuration := float64(0)
        if len(result.Data) > 0 {
            avgDuration = totalDuration / float64(len(result.Data))
        }
        
        stat := UsageStats{
            Platform:      integration["platform"].(string),
            TotalRequests: len(result.Data),
            Successful:    successful,
            Failed:        failed,
            AvgDuration:   avgDuration,
        }
        
        stats = append(stats, stat)
        totalRequests += len(result.Data)
    }
    
    return &CustomerUsage{
        CustomerID: customerID,
        Period: map[string]string{
            "startDate": startDate,
            "endDate":   endDate,
        },
        Integrations: stats,
        Total:        totalRequests,
    }, nil
}
public class UsageStats {
    public String platform;
    public int totalRequests;
    public int successful;
    public int failed;
    public double avgDuration;
}

public class CustomerUsage {
    public String customerId;
    public Map<String, String> period;
    public List<UsageStats> integrations;
    public int total;
}

public CustomerUsage getCustomerUsageStats(
    String customerId, 
    String startDate, 
    String endDate
) throws IOException {
    List<Map<String, Object>> integrations = db.integrations.find(
        Map.of("customerId", customerId)
    );
    
    List<UsageStats> stats = new ArrayList<>();
    int totalRequests = 0;
    
    for (Map<String, Object> integration : integrations) {
        String url = String.format(
            "https://api.requestrocket.com/clients/%s/requests?proxyId=%s&startDate=%s&endDate=%s",
            SAAS_CLIENT_ID,
            integration.get("proxyId"),
            startDate,
            endDate
        );
        
        Request request = new Request.Builder()
            .url(url)
            .header("Authorization", RR_USER_TOKEN)
            .get()
            .build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            String json = response.body().string();
            JsonObject result = gson.fromJson(json, JsonObject.class);
            JsonArray data = result.getAsJsonArray("data");
            
            int successful = 0;
            int failed = 0;
            double totalDuration = 0;
            
            for (JsonElement element : data) {
                JsonObject req = element.getAsJsonObject();
                String status = req.get("status").getAsString();
                
                if ("completed".equals(status)) {
                    successful++;
                } else if ("failed".equals(status)) {
                    failed++;
                }
                
                totalDuration += req.get("duration").getAsDouble();
            }
            
            UsageStats stat = new UsageStats();
            stat.platform = (String) integration.get("platform");
            stat.totalRequests = data.size();
            stat.successful = successful;
            stat.failed = failed;
            stat.avgDuration = data.size() > 0 ? totalDuration / data.size() : 0;
            
            stats.add(stat);
            totalRequests += data.size();
        }
    }
    
    CustomerUsage usage = new CustomerUsage();
    usage.customerId = customerId;
    usage.period = Map.of("startDate", startDate, "endDate", endDate);
    usage.integrations = stats;
    usage.total = totalRequests;
    
    return usage;
}

Complete Example: Integration Marketplace

Here's a full example of building an integration marketplace:

// marketplace.js - Initialize your marketplace
class IntegrationMarketplace {
  constructor(rrUserToken, saasClientId) {
    this.rrToken = rrUserToken;
    this.clientId = saasClientId;
  }

  async listAvailableIntegrations() {
    return [
      {
        id: 'stripe',
        name: 'Stripe',
        description: 'Accept payments and manage subscriptions',
        authType: 'oauth2',
        targetUrl: 'https://api.stripe.com',
        icon: '/icons/stripe.svg'
      },
      {
        id: 'shopify',
        name: 'Shopify',
        description: 'Sync orders and inventory',
        authType: 'apiKey',
        targetUrl: 'https://api.shopify.com',
        icon: '/icons/shopify.svg'
      },
      // ... more integrations
    ];
  }

  async ensureTarget(platformId, platformConfig) {
    // Check if target exists
    const response = await fetch(
      `https://api.requestrocket.com/clients/${this.clientId}/targets`,
      {
        headers: { 'Authorization': this.rrToken }
      }
    );
    
    const targets = await response.json();
    const existing = targets.find(t => t.targetName === platformId);
    
    if (existing) return existing;
    
    // Create target
    return await fetch(
      `https://api.requestrocket.com/clients/${this.clientId}/targets`,
      {
        method: 'POST',
        headers: {
          'Authorization': this.rrToken,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          targetName: platformId,
          region: 'us-east-1',
          baseURL: platformConfig.targetUrl,
          testPath: '/health'
        })
      }
    ).then(r => r.json());
  }
}
// Connect customer to integration
async function connectIntegration(customerId, platformId, credentials) {
  const marketplace = new IntegrationMarketplace(
    process.env.RR_TOKEN,
    process.env.SAAS_CLIENT_ID
  );
  
  // Get platform config
  const platforms = await marketplace.listAvailableIntegrations();
  const platform = platforms.find(p => p.id === platformId);
  
  if (!platform) {
    throw new Error('Platform not found');
  }
  
  // Ensure target exists
  const target = await marketplace.ensureTarget(platformId, platform);
  
  // Create customer-specific proxy credential
  const proxyKey = crypto.randomBytes(32).toString('hex');
  const proxyCred = await createCredential(this.clientId, {
    credentialName: `${customerId}-${platformId}-proxy`,
    credentialType: 'proxy',
    authType: 'apiKey',
    region: 'us-east-1',
    secret: {
      keyName: 'X-API-Key',
      keyValue: proxyKey
    }
  });
  
  // Create target credential with customer's creds
  const targetCred = await createCredential(this.clientId, {
    credentialName: `${customerId}-${platformId}-target`,
    credentialType: 'target',
    authType: platform.authType,
    region: 'us-east-1',
    secret: credentials
  });
  
  // Create proxy
  const proxy = await createProxy(this.clientId, {
    proxyName: `${customerId}-${platformId}`,
    region: 'us-east-1',
    proxyCredentialId: proxyCred.credentialId,
    targetId: target.targetId,
    targetCredentialId: targetCred.credentialId,
    active: true
  });
  
  // Save to database
  await db.integrations.create({
    customerId,
    platformId,
    platformName: platform.name,
    proxyId: proxy.proxyId,
    proxyUrl: proxy.baseURL,
    apiKey: proxyKey,
    status: 'active',
    connectedAt: new Date()
  });
  
  return {
    integration: {
      platform: platform.name,
      proxyUrl: proxy.baseURL,
      apiKey: proxyKey
    }
  };
}
// Sync data for customer
async function syncIntegrationData(customerId, platformId) {
  const integration = await db.integrations.findOne({
    customerId,
    platformId,
    status: 'active'
  });
  
  if (!integration) {
    throw new Error('Integration not found or inactive');
  }
  
  try {
    // Fetch data from third-party via proxy
    const response = await fetch(
      `${integration.proxyUrl}/api/data`,
      {
        headers: {
          'Authorization': `Bearer ${integration.apiKey}`,
          'Content-Type': 'application/json'
        }
      }
    );
    
    if (!response.ok) {
      throw new Error(`Sync failed: ${response.status}`);
    }
    
    const data = await response.json();
    
    // Process and store data
    await processIntegrationData(customerId, platformId, data);
    
    // Update sync status
    await db.integrations.update(integration.id, {
      lastSyncedAt: new Date(),
      lastSyncStatus: 'success'
    });
    
    return { success: true, recordCount: data.length };
    
  } catch (error) {
    await db.integrations.update(integration.id, {
      lastSyncedAt: new Date(),
      lastSyncStatus: 'failed',
      lastSyncError: error.message
    });
    
    throw error;
  }
}
// Dashboard endpoint for customer
app.get('/api/integrations/dashboard', 
  authenticateCustomer, 
  async (req, res) => {
    const { customerId } = req.user;
    
    // Get all customer integrations
    const integrations = await db.integrations.find({ customerId });
    
    // Get usage stats for each
    const stats = await Promise.all(
      integrations.map(async (integration) => {
        const last24h = new Date(Date.now() - 24 * 60 * 60 * 1000);
        
        const response = await fetch(
          `https://api.requestrocket.com/clients/${SAAS_CLIENT_ID}/requests?` +
          `proxyId=${integration.proxyId}&startDate=${last24h.toISOString()}`,
          {
            headers: { 'Authorization': process.env.RR_TOKEN }
          }
        );
        
        const { data } = await response.json();
        
        return {
          platform: integration.platformName,
          status: integration.status,
          lastSync: integration.lastSyncedAt,
          requests24h: data.length,
          successRate: data.length > 0 
            ? (data.filter(r => r.status === 'completed').length / data.length) * 100
            : 100
        };
      })
    );
    
    res.json({
      integrations: stats,
      totalIntegrations: integrations.length,
      activeIntegrations: integrations.filter(i => i.status === 'active').length
    });
  }
);

Pricing Considerations

When building on RequestRocket:

  1. Plan for Scale: Request volumes add up across all customers
  2. Monitor Usage: Track usage per customer for potential charge-backs
  3. Consider Tiers: Different customer tiers may need different plans
  4. Cache Wisely: Reduce redundant requests to save costs

Security Checklist

  • ✅ Never expose RequestRocket user tokens to customers
  • ✅ Use unique proxy credentials per customer
  • ✅ Implement authorization rules for access control
  • ✅ Rotate credentials regularly
  • ✅ Monitor for unusual activity
  • ✅ Audit access logs periodically
  • ✅ Encrypt data in transit and at rest
  • ✅ Follow least privilege principle

Need help architecting your SaaS integration strategy? Contact our solutions team for consultation.

Next Steps

On this page