Customer API
Solar 4 RVs Customer API
A JSON API for approved customer integrations. It gives authenticated customers product stock and ex-GST B2B pricing for their assigned company location, plus controlled order creation from SKUs.

Overview
What this API includes
Base URLs
https://api.solar4rvs.com.au
Available endpoints
GET /products— allACTIVEOnline Store-visible products with SKU, stock, ex-GST prices, breakpoints, dimensions, barcode, brand, weight in kg, and update timestampPOST /order— creates an order from SKU quantities after overdue-invoice and credit-limit checks- No per-SKU read filters
Versioning
- The current public endpoints are
/productsand/order - Breaking changes will go into a new versioned path
- Current schema is published at
/openapi
Quickstart
Make your first request in 5 steps
- Create your company API key from Solar 4 RVs within your account settings after logging in.
- Store the key in your server-side integration as a secret.
- Send the key as
Authorization: Bearer ...and include your approved company email inX-Customer-Email. - If the key is expired, extend it from your account settings back to 2 years.
- Call
/productsfor catalogue sync or/orderto submit an order.
Authentication
Required headers
| Header | Required | Description |
|---|---|---|
Authorization |
Yes | Bearer YOUR_API_KEY |
X-Customer-Email |
Yes | The approved company email address linked to the issued API key. |
Endpoints
Request reference
GET
/products
Returns one flat array of product rows with total
quantity, ex-GST price, breakpoints, barcode, brand, weight in kilograms, shipping dimensions in metres, and update timestamp.- No query parameters
- JSON response only
- Rate limited to 1 request per 15 seconds, 15 per hour, and 360 per day
- Weight is always in kilograms and shipping dimensions are always in metres
- Items that are not stock tracked, but generally always in stock, will show a quantity of 9999
POST
/order
Creates an order, or optionally a draft order for costing, from PO, address, SKU quantities, order type, courier type, and optional authority-to-leave.
- No query parameters
- JSON request and response only
- Blocks creation when the company has overdue invoices or is already over its approved credit limit
- Reusing a PO that already exists on a completed order, or while an order is already being created with that PO, returns
409 duplicate_poand no new order is created, this key is suggested to be used for idempotency - Set
draftOnlytotrueto create a draft order, return the full costing response, and skip converting the draft into an order - Draft-only requests can reuse the same PO repeatedly until a completed order exists for that PO, unless a completed order is currently being created with the same PO
- Optional
address.companyis supported for the shipping address company name - Optional
address2is supported for unit, suite, or apartment details - Use
stateandpostcode;VICandVictoriaare both accepted, and the postcode must be a real four-digit Australian postcode that matches the supplied state - Country is fixed to Australia
authorityToLeaveis optional and defaults totrue- Rate limited to 1 request per 2 minutes
- Response includes the created order name, or draft order name when
draftOnlyis true, plus line-item costs, shipping costs, total ex GST, and total incl GST - Internal platform IDs are not returned in the public response
courierType: "express"will use either Express Australia Post or an expedited courier service;courierType: "regular"will use Regular Australia Post or a standard courier service; when one option is not available, the other will be used
Examples
Example requests
cURL — products
curl "https://api.solar4rvs.com.au/products" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "X-Customer-Email: [email protected]"
Node.js fetch example
const response = await fetch("https://api.solar4rvs.com.au/products", {
headers: {
Authorization: "Bearer " + process.env.CUSTOMER_API_KEY,
"X-Customer-Email": process.env.CUSTOMER_API_EMAIL,
},
});
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
const payload = await response.json();
console.log(payload.length);
cURL — order
curl "https://api.solar4rvs.com.au/order" \
-X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "X-Customer-Email: [email protected]" \
-H "Content-Type: application/json" \
--data '{
"po": "PO-1001",
"address": {
"firstName": "Alex",
"lastName": "Buyer",
"company": "Acme RV Services",
"address1": "1 Example Street",
"address2": "Unit 4",
"city": "Melbourne",
"state": "VIC",
"postcode": "3000"
},
"lines": [{ "sku": "ABC-123", "quantity": 2 }],
"orderType": "dropship",
"courierType": "express",
"draftOnly": true
}'
Responses
Example JSON
Products response
[
{
"sku": "ABC-123",
"productTitle": "Example Product",
"barcode": "1234567890123",
"brand": "Example Brand",
"quantity": 12,
"price": "90.91",
"breakpoints": [
{
"min_qty": 10,
"price": "55.00"
},
{
"min_qty": 20,
"price": "54.00"
}
],
"weight": 1.25,
"shipping": {
"length": 0.5,
"width": 0.3,
"height": 0.2
},
"updatedAt": "2026-05-07T00:00:00.000Z"
}
]
Order response
{
"po": "PO-1001",
"name": "#S278743",
"address": {
"firstName": "Alex",
"lastName": "Buyer",
"company": "Acme RV Services",
"address1": "1 Example Street",
"address2": "Unit 4",
"city": "Melbourne",
"state": "Victoria",
"postcode": "3000",
"phone": "0400000000"
},
"skus": [
{
"sku": "ABC-123",
"quantity": 2
}
],
"orderType": "dropship",
"courierType": "express",
"authorityToLeave": true,
"draftOnly": false,
"currencyCode": "AUD",
"costs": {
"lineItems": [
{
"sku": "ABC-123",
"productTitle": "Example Product",
"quantity": 2,
"unitCostExGst": "2.16",
"lineItemCostExGst": "4.32",
"lineItemCostInclGst": "4.75"
}
],
"shippingCostExGst": "12.95",
"shippingCostInclGst": "14.25",
"totalExGst": "17.27",
"totalInclGst": "19.00",
"gst": "1.73"
},
"account": {
"companyName": "Example Company",
"creditLimit": "500.00",
"outstandingBeforeOrder": "0.00",
"overdueInvoices": []
}
}
Errors & limits
Failure handling
| Status | Code | When it happens | Recommended handling |
|---|---|---|---|
| 400 | query_parameters_not_supported | Query parameters were sent to a fixed endpoint. | Remove query parameters and call the endpoint exactly as documented. |
| 401 | invalid_auth_headers / invalid_credentials / expired_credentials | Email or key is missing, invalid, expired, or not recognised. | Check the email, key, and credential status. Expired keys must be renewed before retrying. |
| 403 | insufficient_scope / ip_not_allowed | The key is valid but does not include access to the endpoint being called, or it is restricted to different source IPs. | Use a key with /products access for catalogue sync and /order access for order creation, or ask for a new credential. |
| 402 | account_overdue / credit_limit_exceeded | The account has overdue invoices or is already over its approved credit limit before the order is created. | Resolve the account balance before retrying. |
| 409 | duplicate_po | An existing completed order for the authenticated company already uses the submitted PO number, or an order with that PO is already being created. | Treat PO as an idempotency key for completed order creation. Draft-only costing calls can reuse the same PO until an order is created or being created. |
| 422 | shipping_address_invalid / shipping_rate_unavailable / draft_order_create_failed | Shipping address cannot be validated, no shipping rate is available, or our system rejects the order. | Check the shipping address, wait a few minutes if the shipping service is unavailable, or contact us with the address location. |
| 404 | not_found | The request path is not one of the documented API or docs paths. | Use exactly /products, /order, /docs, or /openapi. |
| 405 | method_not_allowed | A method other than the documented method was sent to an endpoint. | Use GET for /products and POST for /order. |
| 413 | payload_too_large | A request body exceeds the edge limit. | Keep order payloads small and do not send bodies to read endpoints. |
| 429 | rate_limited | Too many requests were made too quickly. /products allows 1 request per 15 seconds, 15 per hour, and 360 per day. /order allows 1 request per 2 minutes. | Wait for the Retry-After header before retrying. |
| 500 | products_unavailable / order_unavailable | Temporary platform or upstream failure. | Retry later and include the request id if you contact support. |
Example permission error response
{
"error": {
"code": "insufficient_scope",
"message": "This API key does not include access to /products."
}
}
This is returned when an order-only key calls /products. Calling /order with a product-only key returns the same 403 insufficient_scope structure with the message This API key cannot create orders.
Example rate limit response
{
"error": {
"code": "rate_limited",
"message": "Too many order API requests. Try again shortly."
}
}
Operational notes
- Keys can be granted access to
/products,/order, or both. Calling an endpoint the key does not include returns403 insufficient_scope. - Rate limits are enforced in Redis per credential, customer email, and source IP.
/productsis capped at 1 request per 15 seconds, 15 per hour, and 360 per day./orderis capped at 1 request per 2 minutes.- Weight values are normalised to kilograms. Shipping
length,width, andheightare read from product metafields and normalized to metres. - Expired keys return
401 expired_credentialsuntil they are extended back to 2 years. - A
429response includes aRetry-Afterheader.
Support
Troubleshooting and help
- Include the request timestamp and any
X-Request-Idvalue captured by your integration. - Tell support you were calling
/products. - If you suspect a leaked key, revoke it immediately and issue a replacement.
- Use the published machine-readable schema at
/openapifor tooling, Postman imports, or connector generation.