Protocol Buffers

Protocol Buffers

Overview

PSRESTful supports binary Protocol Buffer (protobuf) responses as an alternative to JSON on a subset of read-only endpoints. Protobuf encodes data into a compact binary format that is smaller on the wire and faster to parse than JSON — making it a good fit for high-volume integrations that process large catalogs or poll inventory frequently.

For typical usage (browsing docs, calling a few endpoints, debugging) JSON is the better choice. Protobuf is worth considering when you are:

  • Importing large product catalogs across many suppliers where every kilobyte and millisecond adds up
  • Polling inventory at high frequency and want to minimize bandwidth and parse time
  • Building server-to-server pipelines where human readability is not a concern

How It Works

PSRESTful uses standard HTTP content negotiation:

  1. Your client sends an Accept: application/protobuf header with the request
  2. The API serializes the response into the binary protobuf format
  3. The response is returned with a Content-Type: application/protobuf header
  4. Your client deserializes the binary payload using the matching proto definition

If no Accept header is sent (or the value is application/json), the response is returned as JSON as usual.

Supported Endpoints

⚠️

Protobuf responses are only available on the read-only endpoints listed below. All other endpoints return JSON regardless of the Accept header.

ServiceVersionEndpoint PathResponse Message
Inventory1.2.1/v1.2.1/suppliers/{id}/inventory/inventory.v1.GetInventoryLevelsResponse
Inventory2.0.0/v2.0.0/suppliers/{id}/inventory/inventory.v2.GetInventoryLevelsResponse
Product Data1.0.0/v1.0.0/suppliers/{id}/products/{productId}/product.v1.GetProductResponse
Product Data2.0.0/v2.0.0/suppliers/{id}/products/{productId}/product.v2.GetProductResponse
Media Content1.0.0/v1.0.0/suppliers/{id}/media/media.v1.GetMediaContentResponse
Media Content1.1.0/v1.1.0/suppliers/{id}/media/media.v1.GetMediaContentResponse
PPC1.0.0/v1.0.0/suppliers/{id}/ppc/decoration-colors/ppc.v1.GetDecorationColorsResponse
PPC1.0.0/v1.0.0/suppliers/{id}/ppc/fob-points/ppc.v1.GetFobPointsResponse
PPC1.0.0/v1.0.0/suppliers/{id}/ppc/available-locations/ppc.v1.GetAvailableLocationsResponse
PPC1.0.0/v1.0.0/suppliers/{id}/ppc/available-charges/ppc.v1.GetAvailableChargesResponse
PPC1.0.0/v1.0.0/suppliers/{id}/ppc/pricing-and-configuration/ppc.v1.GetConfigurationAndPricingResponse

JSON vs Protobuf Comparison

FactorJSONProtobuf
Content typeapplication/jsonapplication/protobuf
Human-readableYesNo (binary)
Payload sizeLarger (text with field names)Smaller (binary with field numbers)
Parse speedSlowerFaster
Schema requiredNoYes (proto definitions)
Browser supportNative (response.json())Requires a protobuf library
Endpoint coverageAll endpoints11 read-only endpoints

Example Requests

curl -s \
  -H "X-API-Key: your-api-key" \
  -H "Accept: application/protobuf" \
  -o response.bin \
  "https://api.psrestful.com/v2.0.0/suppliers/HIT/inventory/?productId=5989"

The response headers will include:

Content-Type: application/protobuf

Deserializing Responses

Python — using psdomain

The psdomain package ships the compiled proto definitions for every supported service. Install it and use the generated message classes to parse the binary response.

pip install psdomain
import requests
from psdomain.proto.inventory.v2 import GetInventoryLevelsResponse
 
response = requests.get(
    "https://api.psrestful.com/v2.0.0/suppliers/HIT/inventory/",
    params={"productId": "5989"},
    headers={
        "X-API-Key": "your-api-key",
        "Accept": "application/protobuf",
    },
)
 
inventory = GetInventoryLevelsResponse()
inventory.ParseFromString(response.content)
 
for part in inventory.inventory.part_inventory_array:
    print(f"{part.part_id}: {part.quantity_available.quantity.value}")

JavaScript — using protobufjs

You can load the .proto definition files and decode the binary response with protobufjs.

import protobuf from "protobufjs";
 
// Load the proto definition (download from psdomain or vendor into your project)
const root = await protobuf.load("inventory_v2.proto");
const ResponseType = root.lookupType(
  "inventory.v2.GetInventoryLevelsResponse"
);
 
const response = await fetch(
  "https://api.psrestful.com/v2.0.0/suppliers/HIT/inventory/?productId=5989",
  {
    headers: {
      "X-API-Key": "your-api-key",
      "Accept": "application/protobuf",
    },
  }
);
 
const buffer = await response.arrayBuffer();
const inventory = ResponseType.decode(new Uint8Array(buffer));
 
for (const part of inventory.inventory.partInventoryArray) {
  console.log(`${part.partId}: ${part.quantityAvailable.quantity.value}`);
}

Combining with Compression

Protobuf responses can be compressed just like JSON responses. Send both headers together for the smallest possible payload:

curl -s \
  -H "X-API-Key: your-api-key" \
  -H "Accept: application/protobuf" \
  -H "Accept-Encoding: zstd, br, gzip" \
  -o response.bin \
  "https://api.psrestful.com/v2.0.0/suppliers/HIT/inventory/?productId=5989"

See Compression for more details on supported encoding methods.

Trade-offs

FactorJSONProtobuf
Ease of useSimple — parse with built-in methodsRequires proto definitions and a library
DebuggingEasy — readable in logs and browsersHarder — binary requires tooling to inspect
Payload sizeLargerSmaller (typically 30–50% reduction)
Parse performanceGoodFaster (especially for large responses)
Endpoint supportAll endpoints11 read-only endpoints

Best Practices

  1. Start with JSON, upgrade selectively. Use JSON for development, testing, and low-volume calls. Switch to protobuf only for the specific endpoints where payload size or parse time is a bottleneck.

  2. Combine with compression. Protobuf + gzip (or Brotli/Zstandard) gives you the smallest possible transfer size. See Compression.

  3. Pin proto definitions to the API version. The proto message schemas correspond to specific PSRESTful API versions. When you upgrade to a new API version, update your psdomain package to match.

  4. Check the Content-Type header for fallback. If the server cannot produce a protobuf response (unsupported endpoint, server error), it will return JSON instead. Always check Content-Type before deserializing:

if response.headers["Content-Type"] == "application/protobuf":
    inventory = GetInventoryLevelsResponse()
    inventory.ParseFromString(response.content)
else:
    inventory = response.json()
  • Compression — HTTP compression with gzip, Brotli, and Zstandard
  • Caching — API response caching and cache bypass
  • Rate Limits — API usage limits