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 — all ACTIVE Online Store-visible products with SKU, stock, ex-GST prices, breakpoints, dimensions, barcode, brand, weight in kg, and update timestamp
  • POST /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 /products and /order
  • Breaking changes will go into a new versioned path
  • Current schema is published at /openapi
Quickstart

Make your first request in 5 steps

  1. Create your company API key from Solar 4 RVs within your account settings after logging in.
  2. Store the key in your server-side integration as a secret.
  3. Send the key as Authorization: Bearer ... and include your approved company email in X-Customer-Email.
  4. If the key is expired, extend it from your account settings back to 2 years.
  5. Call /products for catalogue sync or /order to submit an order.
Authentication

Required headers

HeaderRequiredDescription
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_po and no new order is created, this key is suggested to be used for idempotency
  • Set draftOnly to true to 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.company is supported for the shipping address company name
  • Optional address2 is supported for unit, suite, or apartment details
  • Use state and postcode; VIC and Victoria are both accepted, and the postcode must be a real four-digit Australian postcode that matches the supplied state
  • Country is fixed to Australia
  • authorityToLeave is optional and defaults to true
  • Rate limited to 1 request per 2 minutes
  • Response includes the created order name, or draft order name when draftOnly is 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

StatusCodeWhen it happensRecommended handling
400query_parameters_not_supportedQuery parameters were sent to a fixed endpoint.Remove query parameters and call the endpoint exactly as documented.
401invalid_auth_headers / invalid_credentials / expired_credentialsEmail or key is missing, invalid, expired, or not recognised.Check the email, key, and credential status. Expired keys must be renewed before retrying.
403insufficient_scope / ip_not_allowedThe 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.
402account_overdue / credit_limit_exceededThe account has overdue invoices or is already over its approved credit limit before the order is created.Resolve the account balance before retrying.
409duplicate_poAn 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.
422shipping_address_invalid / shipping_rate_unavailable / draft_order_create_failedShipping 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.
404not_foundThe request path is not one of the documented API or docs paths.Use exactly /products, /order, /docs, or /openapi.
405method_not_allowedA method other than the documented method was sent to an endpoint.Use GET for /products and POST for /order.
413payload_too_largeA request body exceeds the edge limit.Keep order payloads small and do not send bodies to read endpoints.
429rate_limitedToo 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.
500products_unavailable / order_unavailableTemporary 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 returns 403 insufficient_scope.
  • Rate limits are enforced in Redis per credential, customer email, and source IP.
  • /products is capped at 1 request per 15 seconds, 15 per hour, and 360 per day.
  • /order is capped at 1 request per 2 minutes.
  • Weight values are normalised to kilograms. Shipping length, width, and height are read from product metafields and normalized to metres.
  • Expired keys return 401 expired_credentials until they are extended back to 2 years.
  • A 429 response includes a Retry-After header.
Support

Troubleshooting and help