Rate Quotes - Developer Guide

Get instant shipping rate quotes before creating an order. Calculate delivery costs based on service level, package dimensions, weight, and destination. Perfect for displaying shipping options to your customers.

View in Swagger UI API Reference

Overview

The POST /v1/rates/quote endpoint calculates delivery rates without creating an order. Use this to show customers shipping options and prices before checkout.

POST /v1/rates/quote

Returns rate quote with price, estimated delivery date, and transit time. Requires HMAC authentication.

đŸ’¡ Use Case: Display shipping options to customers during checkout. Get quotes for different service levels (standard, express, same_day) to let customers choose their preferred delivery speed.

Request Body Structure

The rate quote request requires the following fields:

Field Type Required Description
service_level string Yes One of: standard, express, same_day
pickup object Yes Pickup location (name, phone, email, address, time_window)
dropoff object Yes Delivery location (name, phone, email, address, time_window)
parcels array Yes Array of parcels with dimensions, weight, and value
Note: The request structure is similar to order creation, but you don't need partner_order_id or idempotency_key for rate quotes.

Code Examples

Python

Python Example
import hmac
import hashlib
import time
import json
import requests

def get_rate_quote():
    # Configuration
    public_key = "pk_test_pivohub"
    secret_key = "sk_test_secret_pivohub"
    base_url = "http://localhost:5000"
    
    # Quote request data
    quote_data = {
        "service_level": "standard",
        "pickup": {
            "name": "Warehouse Montreal",
            "phone": "+1-514-555-0001",
            "email": "warehouse@company.com",
            "address": {
                "line1": "123 Main Street",
                "city": "Montréal",
                "province": "QC",
                "postal_code": "H1A1A1",
                "country": "CA"
            },
            "time_window": {
                "start": "2025-11-08T09:00:00-05:00",
                "end": "2025-11-08T12:00:00-05:00"
            }
        },
        "dropoff": {
            "name": "John Doe",
            "phone": "+1-438-555-0002",
            "email": "john.doe@customer.com",
            "address": {
                "line1": "789 Oak Avenue",
                "city": "Montréal",
                "province": "QC",
                "postal_code": "H2L1P1",
                "country": "CA"
            },
            "time_window": {
                "start": "2025-11-08T13:00:00-05:00",
                "end": "2025-11-08T17:00:00-05:00"
            }
        },
        "parcels": [
            {
                "parcel_id": "PKG-001",
                "description": "Electronics - Laptop",
                "length_cm": 40,
                "width_cm": 30,
                "height_cm": 25,
                "weight_kg": 5.5,
                "value_cents": 150000,
                "fragile": True
            }
        ]
    }
    
    # Prepare request
    method = "POST"
    path = "/v1/rates/quote"
    body = json.dumps(quote_data, separators=(',', ':'))
    timestamp = str(int(time.time()))
    
    # Generate signature
    string_to_sign = f"{timestamp}\n{method}\n{path}\n{body}"
    signature = hmac.new(
        secret_key.encode('utf-8'),
        string_to_sign.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    
    # Make request
    headers = {
        'Content-Type': 'application/json',
        'X-Api-Key': public_key,
        'X-Timestamp': timestamp,
        'X-Signature': f'v1={signature}'
    }
    
    response = requests.post(
        f"{base_url}{path}",
        headers=headers,
        data=body
    )
    
    print(f"Status: {response.status_code}")
    print(f"Response: {json.dumps(response.json(), indent=2)}")
    return response.json()

if __name__ == "__main__":
    get_rate_quote()

JavaScript (Node.js)

JavaScript Example
const crypto = require('crypto');
const axios = require('axios');

async function getRateQuote() {
    // Configuration
    const publicKey = 'pk_test_pivohub';
    const secretKey = 'sk_test_secret_pivohub';
    const baseUrl = 'http://localhost:5000';
    
    // Quote request data
    const quoteData = {
        service_level: 'standard',
        pickup: {
            name: 'Warehouse Montreal',
            phone: '+1-514-555-0001',
            email: 'warehouse@company.com',
            address: {
                line1: '123 Main Street',
                city: 'Montréal',
                province: 'QC',
                postal_code: 'H1A1A1',
                country: 'CA'
            },
            time_window: {
                start: '2025-11-08T09:00:00-05:00',
                end: '2025-11-08T12:00:00-05:00'
            }
        },
        dropoff: {
            name: 'John Doe',
            phone: '+1-438-555-0002',
            email: 'john.doe@customer.com',
            address: {
                line1: '789 Oak Avenue',
                city: 'Montréal',
                province: 'QC',
                postal_code: 'H2L1P1',
                country: 'CA'
            },
            time_window: {
                start: '2025-11-08T13:00:00-05:00',
                end: '2025-11-08T17:00:00-05:00'
            }
        },
        parcels: [{
            parcel_id: 'PKG-001',
            description: 'Electronics - Laptop',
            length_cm: 40,
            width_cm: 30,
            height_cm: 25,
            weight_kg: 5.5,
            value_cents: 150000,
            fragile: true
        }]
    };
    
    // Prepare request
    const method = 'POST';
    const path = '/v1/rates/quote';
    const body = JSON.stringify(quoteData);
    const timestamp = Math.floor(Date.now() / 1000).toString();
    
    // Generate signature
    const stringToSign = `${timestamp}\n${method}\n${path}\n${body}`;
    const signature = crypto
        .createHmac('sha256', secretKey)
        .update(stringToSign)
        .digest('hex');
    
    // Make request
    const headers = {
        'Content-Type': 'application/json',
        'X-Api-Key': publicKey,
        'X-Timestamp': timestamp,
        'X-Signature': `v1=${signature}`
    };
    
    try {
        const response = await axios.post(
            `${baseUrl}${path}`,
            quoteData,
            { headers }
        );
        
        console.log('Status:', response.status);
        console.log('Rate Quote:', JSON.stringify(response.data, null, 2));
        return response.data;
    } catch (error) {
        console.error('Error:', error.response?.data || error.message);
        throw error;
    }
}

getRateQuote();

cURL

cURL Example
#!/bin/bash

# Configuration
PUBLIC_KEY="pk_test_pivohub"
SECRET_KEY="sk_test_secret_pivohub"
BASE_URL="http://localhost:5000"
TIMESTAMP=$(date +%s)

# Quote request data
QUOTE_DATA='{
  "service_level": "standard",
  "pickup": {
    "name": "Warehouse Montreal",
    "phone": "+1-514-555-0001",
    "email": "warehouse@company.com",
    "address": {
      "line1": "123 Main Street",
      "city": "Montréal",
      "province": "QC",
      "postal_code": "H1A1A1",
      "country": "CA"
    },
    "time_window": {
      "start": "2025-11-08T09:00:00-05:00",
      "end": "2025-11-08T12:00:00-05:00"
    }
  },
  "dropoff": {
    "name": "John Doe",
    "phone": "+1-438-555-0002",
    "email": "john.doe@customer.com",
    "address": {
      "line1": "789 Oak Avenue",
      "city": "Montréal",
      "province": "QC",
      "postal_code": "H2L1P1",
      "country": "CA"
    },
    "time_window": {
      "start": "2025-11-08T13:00:00-05:00",
      "end": "2025-11-08T17:00:00-05:00"
    }
  },
  "parcels": [{
    "parcel_id": "PKG-001",
    "description": "Electronics - Laptop",
    "length_cm": 40,
    "width_cm": 30,
    "height_cm": 25,
    "weight_kg": 5.5,
    "value_cents": 150000,
    "fragile": true
  }]
}'

# Generate signature
STRING_TO_SIGN="${TIMESTAMP}\nPOST\n/v1/rates/quote\n${QUOTE_DATA}"
SIGNATURE=$(echo -n "$STRING_TO_SIGN" | openssl dgst -sha256 -hmac "$SECRET_KEY" | sed 's/^.* //')
SIGNATURE_HEADER="v1=${SIGNATURE}"

# Make request
curl -X POST "${BASE_URL}/v1/rates/quote" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: ${PUBLIC_KEY}" \
  -H "X-Timestamp: ${TIMESTAMP}" \
  -H "X-Signature: ${SIGNATURE_HEADER}" \
  -d "${QUOTE_DATA}"

Response

On success (200 OK), you'll receive the rate quote:

Success Response (200)
{
  "service_level": "standard",
  "rate_cents": 2500,
  "currency": "CAD",
  "estimated_delivery": "2025-11-11T17:00:00Z",
  "transit_days": 3
}
Field Type Description
service_level string The service level requested (standard, express, same_day)
rate_cents integer Delivery rate in cents (e.g., 2500 = $25.00 CAD)
currency string Currency code (CAD or USD)
estimated_delivery string Estimated delivery date/time (ISO 8601 format)
transit_days integer Number of business days for delivery

Service Level Comparison

Service Level Transit Time Use Case
standard 3-5 business days Regular deliveries, cost-effective
express 1-2 business days Faster delivery, higher priority
same_day Same day Urgent deliveries, premium pricing

Best Practices

Example: Getting Quotes for All Service Levels

Python - Multiple Service Levels
import asyncio
import aiohttp

async def get_all_quotes(pickup, dropoff, parcels):
    """Get rate quotes for all service levels"""
    service_levels = ['standard', 'express', 'same_day']
    quotes = {}
    
    async with aiohttp.ClientSession() as session:
        tasks = []
        for level in service_levels:
            task = get_quote_async(session, level, pickup, dropoff, parcels)
            tasks.append(task)
        
        results = await asyncio.gather(*tasks)
        
        for level, quote in zip(service_levels, results):
            quotes[level] = quote
    
    return quotes

# Display to customer:
# Standard: $25.00 - 3 days
# Express: $37.50 - 1 day  
# Same Day: $50.00 - Today

Next Steps

  1. Create Order: After customer selects a service level, use POST /v1/orders to create the order
  2. Track Order: Use the returned order_id to track delivery status
  3. Set Up Webhooks: Receive real-time updates when order status changes
  4. View Full Documentation: Check out the Swagger UI for interactive API exploration
Try in Swagger UI Creating Orders Guide