Private labeling Lob

Best practices on building atop of Lob's APIs

If you are a company that is building and selling software solutions, you may want to consider leveraging Lob’s direct mail or address verification capabilities to unlock additional value, which can be repackaged and resold as part of your broader offering to your own customers.

In such cases, while there are many ways to integrate with our platform as a backend, the following are some best practices we highly recommend you follow.

Interested in private labeling Lob? Reach out to


Your standard Lob invoice will be a single invoice, broken out into two categories: Subscription (annual) and Usage (monthly). Our resellers often have a need to further segment their usage by different cost centers within their broader organization, in a way that's more reflective of their business operations (e.g. by use case, teams, states, or customer groups). There are two ways to achieve this:

If you have less than 10 cost centers

If you are an Enterprise customer, you may request to modify your invoice to differentiate your monthly usage between various cost centers. Engage your CSM to receive separate invoices.

If you have over 10 cost centers

Another way to segment usage is to attribute your campaign mailings to the responsible cost centers within your organization, so you may accurately keep track during end-of-month reconciliation processes. We recommend using metadata along with page count where applicable.

  • Postcards/self-mailers: When submitting a request to create the mailpiece, include a metadata tag with a key for identifying your billing recipient (e.g., customer_id or institution_id), and insert a value accordingly. This way, you can filter for all the mailings sent by that particular customer or institution later and bill accordingly.

  • Letters/checks: Since the number of pages sent in a campaign may vary and therefore the cost, you will need a way to calculate the final price. Below is a sample (Python) script for how to pull a list of letters by metadata, and parse out the number of pages each.

USAGE: python3

This file will go and fetch mail from the LIST endpoints and basically fetch the letters, load 
them into memory and count the # of pages, Spitting out a CSV with the summary.

from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfinterp import resolve1
from io import BytesIO
import pandas as pd
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
import multiprocessing
from functools import partial
import numpy as np
import requests
import json
import sys

def retry_session(retries, session=None, backoff_factor=1):
    session = session or requests.Session()
    retry = Retry(
        status_forcelist=[500, 502, 503, 504, 429],
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    return session

def parse_pdf(item_list):
    result_csv = pd.DataFrame(columns=['id','page_count','double_sided'])
    session = retry_session(retries=5)
    for item in item_list:
        id = item['id']
        r = session.get(f"{item['url']}")
        if r.status_code in (200,204,202):  
            f = BytesIO(r.content)
            f = PDFParser(f)
            document = PDFDocument(f)
            # This will give you the count of pages
            result_csv = result_csv.append({'id' : id, 'page_count' : resolve1(document.catalog['Pages'])['Count'], 'double_sided' : item['double_sided']}, ignore_index=True)

    return result_csv

def parse_data(api_key):
    url = f""
    creative_url = url
    #TODO: add in any filtering you see fit (metadata, extra services, etc)
    params = {'send_date[gte]' : '2021-10-01', 'send_date[lte]' : '2021-10-12' }
    params['limit'] = '100'

    session = retry_session(retries=5)
    r = session.get(url, auth=requests.auth.HTTPBasicAuth(api_key, ''), params=params)
    j = r.json()
    # print(j)
    results = pd.DataFrame(columns=['id','page_count','double_sided'])

    results = parallelize_data(results, j['data'])

    url = j['next_url']

    #Run through the pagination
    if url is not None:
        while url is not None:
            r = session.get(url, auth=requests.auth.HTTPBasicAuth(api_key, ''))
            j = r.json()
            results = pd.concat([results,parallelize_data(results, j['data'])], ignore_index=True)
            url = j['next_url']

    results.to_csv('results_pdf_parse.csv', index=False)

def parallelize_data(results, data_list):
    num_cores = int(multiprocessing.cpu_count() - 1)  #leave one free to not freeze machine
    num_partitions = num_cores * 2 #number of partitions to split dataframe
    df_split = np.array_split(data_list, num_partitions)
    pool = multiprocessing.Pool(4)
    func = partial(parse_pdf)
    results = pd.concat(, df_split))
    return results

if __name__ == '__main__':
    ##Get API Key
    api_key = input('Enter in your API key (use your live API key to delete live resources): ')


Now that you can identify who is sending mail and the total cost of mailpieces sent by each of your customers, you’re ready to bill them accurately.

Learn more about utilizing metadata tags to segment your mailings.

Try before you buy

In the world of direct mail, there are guidelines and specifications that must be followed to ensure the quality of mailpieces submitted. This is why the auditing process is so important. Your customers will likely want to see the mailpieces they’re submitting before any purchases are made. Lob enables this by providing a test environment along with ways to preview mailpieces:

Use the test environment

With your Lob account, you have access to both a live environment (in which mailpieces will be printed and sent) and a test environment, where you can try our API and view digital proofs without needing to cancel any mailpieces from being delivered. For more information, see Test vs Live Environments.

We recommend that you use the Test environment to create digital proofs which you can then surface back to your customers before submitting Live.

Preview mailpieces

We provide two ways to preview a mailpiece via each form factor’s endpoint. GET(Retrieve) can provide the details of an existing mailpiece (postcard request and response example here).

  1. The url parameter provides a full-scale digital proof of the mailpiece.

2. The thumbnail parameter provides smaller depictions of the mailpiece generated in small, medium, or large sizes.

Give insight into the delivery process

Lob provides visibility of every step of the mail delivery process with mail tracking events, for example “in transit” or “processed for delivery.” In turn, we highly recommend you surface these tracking events back to your end-customers so they can be in the loop as well.

  • GET (Retrieve) can provide the details of an existing mailpiece (postcard GET request and response example here); the tracking_events parameter can be used:

Last updated