Configurations
Configure billing mode, rate discounts, and access settings for your MSP and managed clients
Configurations
The configurations API lets you view your MSP's own settings and fully manage the billing and rate configuration for each of your managed client organisations.
Endpoints
| Method | Endpoint | Description | Min Role |
|---|---|---|---|
| GET | /api/msps/{mspId}/configurations | Get your MSP's own configuration | msp_user |
| PUT | /api/msps/{mspId}/configurations | Update your MSP's own configuration | msp_admin |
| GET | /api/msps/{mspId}/clients/{clientId}/configurations | Get a managed client's configuration | msp_user |
| PUT | /api/msps/{mspId}/clients/{clientId}/configurations | Update a managed client's configuration | msp_admin |
Your MSP's own rate settings (the partner discount floor) are managed by RequestRocket support and cannot be changed via the API. The rates you see in your MSP configuration represent the minimum rates applied to all managed clients.
MSP Configuration
Get MSP Configuration
Retrieve your MSP organisation's own configuration, including your billing type, promotional codes, and partner rate floor.
Request
GET /api/msps/{mspId}/configurations HTTP/1.1
Host: api.requestrocket.com
Authorization: {user_token}Response
{
"configuration": {
"billingType": "stripe",
"billingStatus": "active",
"promotionalCodes": null,
"rates": {
"apiSeconds": 0.0001,
"storageGB": 0.05,
"aiTokens": 0.000002
}
},
"message": "Success"
}Response Fields
| Field | Type | Description |
|---|---|---|
billingType | string | How your MSP is billed: stripe, marketplace, or invoice |
billingStatus | string | Account status: active or suspended |
promotionalCodes | string[] | null | Any active promotional codes |
rates | object | Your MSP's partner discount floor — the minimum rate applied to all clients |
rates.apiSeconds | number | Rate per API second of usage |
rates.storageGB | number | Rate per GB of storage |
rates.aiTokens | number | Rate per AI token |
Example
curl -X GET "https://api.requestrocket.com/api/msps/${MSP_ID}/configurations?configurationType=msp" \
-H "Authorization: ${USER_TOKEN}"const response = await fetch(
`https://api.requestrocket.com/api/msps/${mspId}/configurations?configurationType=msp`,
{
headers: { 'Authorization': process.env.USER_TOKEN }
}
);
const data = await response.json();
console.log('MSP config:', data.configuration);import requests, os
response = requests.get(
f'https://api.requestrocket.com/api/msps/{msp_id}/configurations',
params={'configurationType': 'msp'},
headers={'Authorization': os.getenv('USER_TOKEN')}
)
print(response.json()['configuration'])req, _ := http.NewRequest("GET",
fmt.Sprintf("https://api.requestrocket.com/api/msps/%s/configurations?configurationType=msp", mspId), nil)
req.Header.Set("Authorization", os.Getenv("USER_TOKEN"))
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.requestrocket.com/api/msps/" + mspId + "/configurations?configurationType=msp"))
.header("Authorization", System.getenv("USER_TOKEN"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());Client Configuration
Each managed client has its own configuration that controls who is billed for their usage, what rate discounts apply, and their spending budget.
Get Client Configuration
Retrieve the configuration for a specific managed client.
Request
GET /api/msps/{mspId}/clients/{clientId}/configurations HTTP/1.1
Host: api.requestrocket.com
Authorization: {user_token}Response
{
"configuration": {
"billingType": "stripe",
"billingTo": "msp",
"billingStatus": "active",
"regionAccess": ["us-east-1", "eu-west-1"],
"rates": {
"apiSeconds": 0.00012,
"storageGB": 0.06,
"aiTokens": 0.0000025
},
"budget": {
"current": 45.20,
"autoTopUp": true,
"topUpAmount": 100.00,
"topUpThreshold": 10.00
}
},
"message": "Success"
}Response Fields
| Field | Type | Description |
|---|---|---|
billingType | string | How the client is billed: stripe, marketplace, or invoice |
billingTo | string | Who is charged: "client" (client pays directly) or "msp" (your MSP is charged) |
billingStatus | string | Account status: active or suspended |
regionAccess | string[] | Allowed deployment regions for this client |
rates | object | Rate multipliers for this client. Values are always at or above your MSP rate floor |
budget.current | number | Current available balance |
budget.autoTopUp | boolean | Whether automatic top-ups are enabled |
budget.topUpAmount | number | Amount added per top-up (only when billingTo: "msp") |
budget.topUpThreshold | number | Balance threshold that triggers a top-up (only when billingTo: "msp") |
budget.topUpAmount and budget.topUpThreshold are only editable via PUT when billingTo is "msp". When the client pays directly (billingTo: "client"), the client manages their own top-up settings.
Update Client Configuration
Update billing mode, rate discounts, and — when billing to MSP — budget top-up settings for a managed client.
Rate values below your MSP rate floor are automatically raised to the floor on write — they are not rejected. The effective rate for each metric will always be max(clientRate, mspFloorRate).
Request
PUT /api/msps/{mspId}/clients/{clientId}/configurations HTTP/1.1
Host: api.requestrocket.com
Authorization: {user_token}
Content-Type: application/json
{
"billingTo": "msp",
"rates": {
"apiSeconds": 0.00015,
"storageGB": 0.07,
"aiTokens": 0.000003
},
"budget": {
"autoTopUp": true,
"topUpAmount": 200.00,
"topUpThreshold": 20.00
}
}Request Body
| Field | Type | Required | Description |
|---|---|---|---|
billingTo | string | No | "client" or "msp". Defaults to existing value |
billingType | string | No | Only "stripe" is settable by MSP admins |
rates.apiSeconds | number | No | Rate per API second. Clamped up to MSP floor if below |
rates.storageGB | number | No | Rate per GB of storage. Clamped up to MSP floor if below |
rates.aiTokens | number | No | Rate per AI token. Clamped up to MSP floor if below |
budget.autoTopUp | boolean | No | Enable/disable automatic top-ups (only when billingTo: "msp") |
budget.topUpAmount | number | No | Amount to top up by (only when billingTo: "msp") |
budget.topUpThreshold | number | No | Balance at which a top-up is triggered (only when billingTo: "msp") |
Response
{
"configuration": {
"billingType": "stripe",
"billingTo": "msp",
"billingStatus": "active",
"rates": {
"apiSeconds": 0.00015,
"storageGB": 0.07,
"aiTokens": 0.000003
},
"budget": {
"current": 45.20,
"autoTopUp": true,
"topUpAmount": 200.00,
"topUpThreshold": 20.00
}
},
"message": "Configuration updated successfully"
}Example
curl -X PUT "https://api.requestrocket.com/api/msps/${MSP_ID}/clients/${CLIENT_ID}/configurations" \
-H "Authorization: ${USER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"billingTo": "msp",
"rates": {
"apiSeconds": 0.00015,
"storageGB": 0.07,
"aiTokens": 0.000003
},
"budget": {
"autoTopUp": true,
"topUpAmount": 200.00,
"topUpThreshold": 20.00
}
}'const response = await fetch(
`https://api.requestrocket.com/api/msps/${mspId}/clients/${clientId}/configurations`,
{
method: 'PUT',
headers: {
'Authorization': process.env.USER_TOKEN,
'Content-Type': 'application/json'
},
body: JSON.stringify({
billingTo: 'msp',
rates: { apiSeconds: 0.00015, storageGB: 0.07, aiTokens: 0.000003 },
budget: { autoTopUp: true, topUpAmount: 200.00, topUpThreshold: 20.00 }
})
}
);
const data = await response.json();
console.log('Updated config:', data.configuration);import requests, os
response = requests.put(
f'https://api.requestrocket.com/api/msps/{msp_id}/clients/{client_id}/configurations',
headers={'Authorization': os.getenv('USER_TOKEN')},
json={
'billingTo': 'msp',
'rates': {'apiSeconds': 0.00015, 'storageGB': 0.07, 'aiTokens': 0.000003},
'budget': {'autoTopUp': True, 'topUpAmount': 200.00, 'topUpThreshold': 20.00}
}
)
print(response.json())payload := `{
"billingTo": "msp",
"rates": {"apiSeconds": 0.00015, "storageGB": 0.07, "aiTokens": 0.000003},
"budget": {"autoTopUp": true, "topUpAmount": 200.00, "topUpThreshold": 20.00}
}`
body := bytes.NewBufferString(payload)
req, _ := http.NewRequest("PUT",
fmt.Sprintf("https://api.requestrocket.com/api/msps/%s/clients/%s/configurations", mspId, clientId), body)
req.Header.Set("Authorization", os.Getenv("USER_TOKEN"))
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
fmt.Println(string(respBody))String json = """
{
"billingTo": "msp",
"rates": {"apiSeconds": 0.00015, "storageGB": 0.07, "aiTokens": 0.000003},
"budget": {"autoTopUp": true, "topUpAmount": 200.00, "topUpThreshold": 20.00}
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.requestrocket.com/api/msps/" + mspId + "/clients/" + clientId + "/configurations"))
.header("Authorization", System.getenv("USER_TOKEN"))
.header("Content-Type", "application/json")
.PUT(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());Billing Mode: billingTo
The billingTo field controls which Stripe account is charged for a client's consumption.
| Value | Behaviour |
|---|---|
"client" | The client's own Stripe account is charged. Top-up thresholds are managed by the client. |
"msp" | Your MSP's Stripe account is charged. You control top-up thresholds via this API. |
Switching a client to billingTo: "msp" requires your MSP to have a valid Stripe payment method on file. If no payment method exists, the request will fail with a 400 error.
Switching billingTo does not change which budget balance tracks usage — the client's own budget always records consumption. It only changes which Stripe customer is charged when a top-up occurs.
Rate Floor Clamping
Every client's rates are subject to your MSP's partner discount floor. If you submit a rate value below the floor, it is silently raised to the floor rather than rejected:
effectiveRate = max(submittedRate, mspFloorRate)This means you can safely submit desired client rates without needing to know the exact floor values — the system guarantees the floor is never undercut.
Error Responses
| Status | Message | Cause |
|---|---|---|
| 400 | Input failed data validation | Invalid field types or values in the request body |
| 400 | Cannot bill to MSP: no payment method on file | Switching to billingTo: "msp" but MSP has no Stripe payment method |
| 400 | Cannot bill to MSP: no payment method on file. Please add a payment method... | MSP has a Stripe customer but no saved payment method |
| 404 | Client not found or not linked to this MSP | The clientId does not exist or is not a managed client of this MSP |