Integrating RequestRocket into Your SaaS
Learn how to use RequestRocket to power integrations in your SaaS application
Learn how to use RequestRocket as the integration layer between your SaaS application and third-party platforms.
Contents
- Integration patterns
- Implementation guide
- Advanced patterns
- Webhook forwarding
- Monitoring customer usage
- Security checklist
Review the Security checklist before production use. For plan and usage information, see Plans and billing.
Integration Patterns
Choose whether your SaaS owns every integration, gives customers direct proxy access, or isolates customers in separate RequestRocket organisations.
Pattern 1: Managed Integrations
Your SaaS manages all integrations for customers, storing their third-party credentials securely.
Use Cases:
- 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
- A separate RequestRocket organisation for each customer
Implementation Guide
This section creates an organisation, provisions the records for one customer integration, calls the resulting proxy, and optionally exposes that proxy through your application.
Set Up Your RequestRocket Infrastructure
Create your main SaaS client:
# Create your main SaaS client
curl -X POST "https://api.requestrocket.com/api/clients" \
-H "Authorization: $RR_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clientName": "MySaaS Integration Manager"
}'
# 201
# {
# "clients": [
# {
# "clientId": "b3a1c7d2-5e44-4f0a-9c1e-7d2f8a6b1c90",
# "clientName": "MySaaS Integration Manager",
# "clientMembers": [
# { "userId": "0f8e6c1a-2b7d-4c3e-9a55-1d2e3f4a5b6c", "roles": ["owner", "admin"] }
# ]
# }
# ],
# "message": "client created successfully"
# }// Initialize your SaaS's RequestRocket client
const RR_USER_TOKEN = process.env.RR_USER_TOKEN;
async function initializeSaaS() {
// Create your main client
const response = await fetch('https://api.requestrocket.com/api/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.clients[0].clientId);
return client;
}import requests
import os
RR_USER_TOKEN = os.getenv('RR_USER_TOKEN')
def initialize_saas():
"""Initialize your SaaS's RequestRocket client"""
response = requests.post(
'https://api.requestrocket.com/api/clients',
headers={
'Authorization': RR_USER_TOKEN,
'Content-Type': 'application/json'
},
json={
'clientName': 'MySaaS Integration Manager'
}
)
client = response.json()
print(f'SaaS Client ID: {client["clients"][0]["clientId"]}')
return clientpackage main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
type Client struct {
Clients []struct {
ClientID string `json:"clientId"`
ClientName string `json:"clientName"`
} `json:"clients"`
Message string `json:"message"`
}
func initializeSaaS() (*Client, error) {
rrToken := os.Getenv("RR_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/api/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.Clients[0].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("RR_USER_TOKEN");
private static final OkHttpClient httpClient = new OkHttpClient();
private static final Gson gson = new Gson();
public static class ClientRecord {
public String clientId;
public String clientName;
}
public static class Client {
public ClientRecord[] clients;
public String message;
}
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/api/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.clients[0].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/api/clients/$SAAS_CLIENT_ID/credentials" \
-H "Authorization: $RR_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"credentialName": "customer123-proxy-salesforce",
"credentialType": "proxy",
"credentialAuthType": "key",
"credentialRegion": "us-east-2",
"credentialSecret": {
"key": "Authorization",
"value": "generated-secure-key",
"addToHeader": true
}
}'
# 2. Create target credential (customer's third-party creds)
curl -X POST "https://api.requestrocket.com/api/clients/$SAAS_CLIENT_ID/credentials" \
-H "Authorization: $RR_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"credentialName": "customer123-salesforce-target",
"credentialType": "target",
"credentialAuthType": "none",
"credentialRegion": "us-east-2",
"credentialSecret": {}
}'
# 3. Get or create target
curl -X GET "https://api.requestrocket.com/api/clients/$SAAS_CLIENT_ID/targets" \
-H "Authorization: $RR_USER_TOKEN"
# 4. Create proxy. The response is { "proxies": [ ... ], "message": "Success" }.
# Call it at https://us-east-2.requestrocket.com/api/{proxyId}/{target-path}
curl -X POST "https://api.requestrocket.com/api/clients/$SAAS_CLIENT_ID/proxies" \
-H "Authorization: $RR_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"proxyName": "customer123-salesforce",
"proxyRegion": "us-east-2",
"proxyProxyCredentialId": "inbound-credential-id",
"proxyTargetId": "target-id",
"proxyTargetCredentialId": "target-credential-id",
"proxyActive": true
}'
# Store the returned proxy details in your databaseasync function createCustomerIntegration(customerId, integration) {
const { platform, credentials } = integration;
const customerKey = generateSecureKey();
// 1. Create proxy credential for your customer
const proxyCred = await fetch(
`https://api.requestrocket.com/api/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',
credentialAuthType: 'key',
credentialRegion: 'us-east-2',
credentialSecret: {
key: 'Authorization',
value: customerKey,
addToHeader: true
}
})
}
).then(r => r.json());
// 2. Create target credential (customer's third-party creds)
const targetCred = await fetch(
`https://api.requestrocket.com/api/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',
credentialAuthType: credentials.type, // for example 'oauth2' or 'key'
credentialRegion: 'us-east-2',
credentialSecret: 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/api/clients/${SAAS_CLIENT_ID}/proxies`,
{
method: 'POST',
headers: {
'Authorization': RR_USER_TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify({
proxyName: `${customerId}-${platform}`,
proxyRegion: 'us-east-2',
proxyProxyCredentialId: proxyCred.credentials[0].sKey,
proxyTargetId: target.sKey,
proxyTargetCredentialId: targetCred.credentials[0].sKey,
proxyActive: true
})
}
).then(r => r.json());
// 5. Store mapping in your database
await db.integrations.create({
customerId,
platform,
proxyId: proxy.proxies[0].sKey,
proxyProxyCredentialId: proxyCred.credentials[0].sKey,
proxyUrl: `https://us-east-2.requestrocket.com/api/${proxy.proxies[0].sKey}`,
customerApiKey: customerKey
});
return {
proxyUrl: `https://us-east-2.requestrocket.com/api/${proxy.proxies[0].sKey}`,
apiKey: customerKey
};
}def create_customer_integration(customer_id, integration):
"""Create integration for a new customer"""
platform = integration['platform']
credentials = integration['credentials']
customer_key = generate_secure_key()
# 1. Create proxy credential for your customer
proxy_cred_response = requests.post(
f'https://api.requestrocket.com/api/clients/{SAAS_CLIENT_ID}/credentials',
headers={
'Authorization': RR_USER_TOKEN,
'Content-Type': 'application/json'
},
json={
'credentialName': f'{customer_id}-proxy-{platform}',
'credentialType': 'proxy',
'credentialAuthType': 'key',
'credentialRegion': 'us-east-2',
'credentialSecret': {
'key': 'Authorization',
'value': customer_key,
'addToHeader': True
}
}
)
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/api/clients/{SAAS_CLIENT_ID}/credentials',
headers={
'Authorization': RR_USER_TOKEN,
'Content-Type': 'application/json'
},
json={
'credentialName': f'{customer_id}-{platform}-target',
'credentialType': 'target',
'credentialAuthType': credentials['type'],
'credentialRegion': 'us-east-2',
'credentialSecret': 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/api/clients/{SAAS_CLIENT_ID}/proxies',
headers={
'Authorization': RR_USER_TOKEN,
'Content-Type': 'application/json'
},
json={
'proxyName': f'{customer_id}-{platform}',
'proxyRegion': 'us-east-2',
'proxyProxyCredentialId': proxy_cred['credentials'][0]['sKey'],
'proxyTargetId': target['targets'][0]['sKey'],
'proxyTargetCredentialId': target_cred['credentials'][0]['sKey'],
'proxyActive': True
}
)
proxy = proxy_response.json()
# 5. Store mapping in your database
db.integrations.create({
'customerId': customer_id,
'platform': platform,
'proxyId': proxy['proxies'][0]['sKey'],
'proxyProxyCredentialId': proxy_cred['credentials'][0]['sKey'],
'proxyUrl': f"https://us-east-2.requestrocket.com/api/{proxy['proxies'][0]['sKey']}",
'customerApiKey': customer_key
})
return {
'proxyUrl': f"https://us-east-2.requestrocket.com/api/{proxy['proxies'][0]['sKey']}",
'apiKey': customer_key
}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",
"credentialAuthType": "key",
"credentialRegion": "us-east-2",
"credentialSecret": map[string]interface{}{
"key": "Authorization",
"value": generateSecureKey(),
"addToHeader": true,
},
}
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",
"credentialAuthType": integration.Credentials["type"],
"credentialRegion": "us-east-2",
"credentialSecret": 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),
"proxyRegion": "us-east-2",
"proxyProxyCredentialId": proxyCred["sKey"],
"proxyTargetId": target["sKey"],
"proxyTargetCredentialId": targetCred["sKey"],
"proxyActive": 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"],
"proxyProxyCredentialId": proxyCred["sKey"],
"proxyUrl": fmt.Sprintf("https://us-east-2.requestrocket.com/api/%s", proxy["sKey"]),
"customerApiKey": proxyCred["secret"].(map[string]interface{})["value"],
})
if err != nil {
return nil, err
}
return &IntegrationResult{
ProxyURL: fmt.Sprintf("https://us-east-2.requestrocket.com/api/%s", proxy["sKey"]),
APIKey: proxyCred["secret"].(map[string]interface{})["value"].(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("credentialAuthType", "key");
proxyCredPayload.put("credentialRegion", "us-east-2");
Map<String, Object> proxySecret = new HashMap<>();
proxySecret.put("key", "Authorization");
proxySecret.put("value", generateSecureKey());
proxySecret.put("addToHeader", true);
proxyCredPayload.put("credentialSecret", 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("credentialAuthType", credentials.get("type"));
targetCredPayload.put("credentialRegion", "us-east-2");
targetCredPayload.put("credentialSecret", 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("proxyRegion", "us-east-2");
proxyPayload.put("proxyProxyCredentialId", proxyCred.get("sKey"));
proxyPayload.put("proxyTargetId", target.get("sKey"));
proxyPayload.put("proxyTargetCredentialId", targetCred.get("sKey"));
proxyPayload.put("proxyActive", 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("proxyProxyCredentialId", proxyCred.get("sKey"));
dbRecord.put("proxyUrl", "https://us-east-2.requestrocket.com/api/" + proxy.get("sKey"));
Map<String, String> secret = (Map<String, String>) proxyCred.get("secret");
dbRecord.put("customerApiKey", secret.get("value"));
db.integrations.create(dbRecord);
IntegrationResult result = new IntegrationResult();
result.proxyUrl = "https://us-east-2.requestrocket.com/api/" + proxy.get("sKey");
result.apiKey = secret.get("value");
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-2.requestrocket.com/api/my-proxy/api/customers" \
-H "Authorization: customer-proxy-api-key" \
-H "Content-Type: application/json"
# POST request example
curl -X POST "https://us-east-2.requestrocket.com/api/my-proxy/api/orders" \
-H "Authorization: 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': 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': integration['customerApiKey'],
'Content-Type': 'application/json'
}
)
data = response.json()
# Process and store data
process_customer_data(customer_id, platform, data)
return datafunc 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", 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", 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-2.requestrocket.com/api/my-proxy/orders',
{
headers: {
'Authorization': 'customer-api-key-from-your-saas',
'Content-Type': 'application/json'
}
}
);Advanced Patterns
The following patterns extend the core integration with organisation isolation, request rules, asynchronous delivery, and usage reporting.
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/api/clients" \
-H "Authorization: $RR_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clientName": "Enterprise: Acme Corp"
}'
# 201 { "clients": [{ "clientId": "c4d8e1f0-6a22-4b9c-8d33-1e7a5b0c2d44", "clientName": "Enterprise: Acme Corp", "clientMembers": [] }], "message": "client created successfully" }
# Now create integrations under their dedicated client
curl -X POST "https://api.requestrocket.com/api/clients/c4d8e1f0-6a22-4b9c-8d33-1e7a5b0c2d44/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/api/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.clients[0].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/api/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['clients'][0]['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/api/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.Clients[0].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/api/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.clients[0].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:
# A window limit is a meter, not a rule. See Limits.
# Deny /admin
curl -X POST "https://api.requestrocket.com/api/clients/$SAAS_CLIENT_ID/proxies/$PROXY_ID/rules" \
-H "Authorization: $RR_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"effect": "deny",
"ruleActive": true,
"priority": 800,
"path": { "path": { "pattern": "^/admin/" }, "presence": "must_exist" },
"notes": "Admin endpoints restricted"
}'
# Deny modifications
curl -X POST "https://api.requestrocket.com/api/clients/$SAAS_CLIENT_ID/proxies/$PROXY_ID/rules" \
-H "Authorization: $RR_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"effect": "deny",
"ruleActive": true,
"priority": 850,
"methods": ["DELETE", "PUT"],
"notes": "Read-only access"
}'async function applyCustomerRules(customerId, proxyId, ruleConfig) {
const rules = [];
// Example: Rate limit per customer tier
if (ruleConfig.tier === 'basic') {
rules.push({
effect: 'deny',
ruleActive: true,
priority: 900,
notes: 'A request limit is a meter, not a rule',
});
}
// Example: Restrict certain endpoints
if (ruleConfig.restrictedPaths) {
for (const path of ruleConfig.restrictedPaths) {
rules.push({
effect: 'deny',
ruleActive: true,
priority: 800,
path: { path: { pattern: path }, presence: 'must_exist' },
notes: `Restricted path for ${customerId}`
});
}
}
// Create rules
for (const rule of rules) {
await fetch(
`https://api.requestrocket.com/api/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',
'ruleActive': True,
'priority': 900,
'notes': 'A request limit is a meter, not a rule'
})
# Example: Restrict certain endpoints
if rule_config.get('restrictedPaths'):
for path in rule_config['restrictedPaths']:
rules.append({
'effect': 'deny',
'ruleActive': True,
'priority': 800,
'path': { 'path': { 'pattern': path }, 'presence': 'must_exist' },
'notes': f'Restricted path for {customer_id}'
})
# Example: Method restrictions (read-only)
if rule_config.get('readOnly'):
rules.append({
'effect': 'deny',
'ruleActive': True,
'priority': 850,
'methods': ['DELETE', 'PUT', 'PATCH'],
'notes': f'Read-only access for {customer_id}'
})
# Create rules
for rule in rules:
response = requests.post(
f'https://api.requestrocket.com/api/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",
"ruleActive": true,
"priority": 900,
"notes": "A request limit is a meter, not a rule",
})
}
// Example: Restrict certain endpoints
if restrictedPaths, ok := ruleConfig["restrictedPaths"].([]string); ok {
for _, path := range restrictedPaths {
rules = append(rules, map[string]interface{}{
"effect": "deny",
"ruleActive": true,
"priority": 800,
"path": map[string]interface{}{
"path": map[string]string{"pattern": path},
"presence": "must_exist",
},
"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",
"ruleActive": true,
"priority": 850,
"methods": []string{"DELETE", "PUT", "PATCH"},
"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/api/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("ruleActive", true);
rule.put("priority", 900);
rule.put("notes", "A request limit is a meter, not a rule");
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("ruleActive", true);
rule.put("priority", 800);
Map<String, Object> pathCheck = new HashMap<>();
pathCheck.put("path", Map.of("pattern", path));
pathCheck.put("presence", "must_exist");
rule.put("path", pathCheck);
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("ruleActive", true);
rule.put("methods", List.of("DELETE", "PUT", "PATCH"));
rule.put("notes", "Read-only access for " + customerId);
rules.add(rule);
}
// Create rules
String url = String.format(
"https://api.requestrocket.com/api/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 the Async API when your application accepts work now and RequestRocket should process the proxy request asynchronously. This is the canonical webhook-forwarding example for the developer guides.
# Forward webhook using async endpoint
# Replace /api/ with /async/ in the proxy URL
curl -X POST "https://us-east-2.requestrocket.com/async/my-proxy/webhooks" \
-H "Authorization: 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:
# {
# "message": "Request accepted for async processing",
# "requestId": "f3a6c812-9d04-4e75-b1a8-2c0e5d7f9b31",
# "status": "queued"
# }
# Check webhook delivery status
curl -X GET "https://api.requestrocket.com/api/clients/$SAAS_CLIENT_ID/proxies/$PROXY_ID/requests/$REQUEST_ID" \
-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': 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': 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_idfunc 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", 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", 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
Query request logs for each customer proxy and aggregate the results in your application.
# Get request logs for a specific proxy
curl -X GET "https://api.requestrocket.com/api/clients/$SAAS_CLIENT_ID/proxies/$PROXY_ID/requests" \
-H "Authorization: $RR_USER_TOKEN"
# Response:
# {
# "message": "Success",
# "totalRequests": 1,
# "requests": [
# { "proxyData": { "status": 200, "duration": 0.234 } }
# ]
# }
# 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/api/clients/$SAAS_CLIENT_ID/proxies/$proxy_id/requests" \
-H "Authorization: $RR_USER_TOKEN"
doneasync 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/api/clients/${SAAS_CLIENT_ID}/proxies/${integration.proxyId}/requests?` +
`processedAfter=${startDate}&processedBefore=${endDate}`,
{
headers: { 'Authorization': RR_USER_TOKEN }
}
);
const body = await response.json();
const data = body.requests || [];
return {
platform: integration.platform,
totalRequests: body.totalRequests,
successful: data.filter(r => r.proxyData && r.proxyData.status >= 200 && r.proxyData.status < 300).length,
failed: data.filter(r => r.proxyData && (r.proxyData.status < 200 || r.proxyData.status >= 300)).length,
avgDuration: data.reduce((sum, r) => sum + (r.proxyData?.duration || 0), 0) / (data.length || 1)
};
})
);
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/api/clients/{SAAS_CLIENT_ID}/proxies/{integration['proxyId']}/requests",
params={
'processedAfter': start_date,
'processedBefore': end_date
},
headers={'Authorization': RR_USER_TOKEN}
)
body = response.json()
data = body.get('requests') or []
total_requests = body.get('totalRequests', len(data))
successful = len([r for r in data if 200 <= (r.get('proxyData') or {}).get('status', 0) < 300])
failed = len([r for r in data if (r.get('proxyData') or {}).get('status', 0) >= 300])
avg_duration = sum((r.get('proxyData') or {}).get('duration') or 0 for r in data) / total_requests if total_requests 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/api/clients/%s/proxies/%s/requests?processedAfter=%s&processedBefore=%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 {
TotalRequests int `json:"totalRequests"`
Requests []struct {
ProxyData struct {
Status int `json:"status"`
Duration float64 `json:"duration"`
} `json:"proxyData"`
} `json:"requests"`
}
json.NewDecoder(resp.Body).Decode(&result)
successful := 0
failed := 0
var totalDuration float64
for _, r := range result.Requests {
if r.ProxyData.Status >= 200 && r.ProxyData.Status < 300 {
successful++
} else if r.ProxyData.Status >= 300 {
failed++
}
totalDuration += r.ProxyData.Duration
}
avgDuration := float64(0)
if len(result.Requests) > 0 {
avgDuration = totalDuration / float64(len(result.Requests))
}
stat := UsageStats{
Platform: integration["platform"].(string),
TotalRequests: result.TotalRequests,
Successful: successful,
Failed: failed,
AvgDuration: avgDuration,
}
stats = append(stats, stat)
totalRequests += result.TotalRequests
}
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/api/clients/%s/proxies/%s/requests?processedAfter=%s&processedBefore=%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("requests");
int successful = 0;
int failed = 0;
double totalDuration = 0;
for (JsonElement element : data) {
JsonObject proxyData = element.getAsJsonObject().getAsJsonObject("proxyData");
int status = proxyData.get("status").getAsInt();
if (status >= 200 && status < 300) {
successful++;
} else if (status >= 300) {
failed++;
}
if (proxyData.has("duration") && !proxyData.get("duration").isJsonNull()) {
totalDuration += proxyData.get("duration").getAsDouble();
}
}
UsageStats stat = new UsageStats();
stat.platform = (String) integration.get("platform");
stat.totalRequests = result.get("totalRequests").getAsInt();
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;
}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