LightBox Parcels with Multiple Owners

This sample demonstrates how to identify properties with multiple owners using the LightBox API. It includes a Jupyter Notebook walkthrough and a runnable Python script.

Jupyter Notebook

View Raw

LightBox API - Multi-dwelling Assessment Logic

Use an address to acquire its location coordinates, then use those coordinates to find an associated property parcel, then use that parcel to find associated tax assessment data.

For multi-dwelling properties, a given address will have a one-to-many relationship with the assessment data. The assessment data may contain assessements for multiple addresses within the same dwelling.

Using Addresses to Find Tax Assessment Data

This notebook demonstrates basic features of the LightBox Geocoding API by walking through the following steps:

  1. Import Python packages
  2. Enter your API Key for authorization
  3. Create request objects and display the results both in the JSON form.

Additional Materials: LightBox Developer Portal

#1. Import the required python packages

1import requests
2import json
3from typing import Dict
4import pandas as pd
5

#2. Import function definitions

1# ----------------------------
2# Function Definitions
3# ----------------------------
4
5# Function to geocode a single address using the LightBox API.
6def geocode_address(lightbox_api_key: str, address: str) -> Dict:
7    """
8    Geocodes the provided address using the LightBox API.
9    
10    Args:
11        lightbox_api_key (str): The API key for accessing the LightBox API.
12        address (str): The address string for matching.
13    
14    Returns:
15        dict: The geocoded address information in JSON format.
16    """
17    # API endpoint configuration
18    BASE_URL = "https://api.lightboxre.com/v1"
19    ENDPOINT = "/addresses/search"
20    URL = BASE_URL + ENDPOINT
21
22    # Setting up request parameters and headers
23    params = {"text": address}
24    headers = {"x-api-key": lightbox_api_key}
25
26    # Sending request to the LightBox API
27    geocoder_data = requests.get(URL, params=params, headers=headers)
28    
29    # Returning the geocoded address information
30    return geocoder_data
31
32
33# Test for the get_parcel_from_lbx_address_id() function
34def get_parcel_data_from_address_coordinates(lightbox_api_key: str, country_code: str, address_wkt_coordinates: str) -> Dict:
35    """
36    Returns a dictionary containing the parcel data for the specified address.
37
38    Args:
39        lightbox_api_key (str): The API key for accessing the LightBox API.
40        country_code (str): The country code for the address.
41        address_wkt_coordinates (str): The address coordinates for the address.
42    """
43
44    # API endpoint configuration
45    BASE_URL = "https://api.lightboxre.com/v1"
46    ENDPOINT = f"/parcels/{country_code}/geometry"
47    URL = BASE_URL + ENDPOINT
48
49    # Setting up request parameters and headers
50    params = {"wkt": address_wkt_coordinates}
51    headers = {"x-api-key": lightbox_api_key}
52
53    # Make the request
54    parcel_data = requests.get(URL, params=params, headers=headers)
55    
56    # Return the parcel data
57    return parcel_data
58
59
60def get_assessment_data_from_lbx_parcel_id(lightbox_api_key: str, parcel_id: str) -> Dict:
61    """
62    Returns a dictionary containing the assessment data for the specified parcel.
63
64    Args:
65        lightbox_api_key (str): The LightBox API key.
66        parcel_id (str): The parcel ID.
67    """
68
69    # API endpoint configuration
70    BASE_URL = "https://api.lightboxre.com/v1"
71    ENDPOINT = f"/assessments/_on/parcel/us/{parcel_id}"
72    URL = BASE_URL + ENDPOINT
73
74    # Setting up request parameters and headers
75    headers = {"x-api-key": lightbox_api_key}
76
77    # Make the request
78    assessment_data = requests.get(URL, headers=headers)
79    
80    # Return the assessment data
81    return assessment_data
82

#3. Create variables that will be used to authenticate your calls. Get your key from the LightBox Developer Portal.

1lightbox_api_key = '<YOUR_API_KEY>'

#4. LightBox API Details This notbook will create various requests and display the output in JSON.

  1. Geocoding - https://api.lightboxre.com/v1/addresses/search
  2. Parcels - https://api.lightboxre.com/v1/parcels/{country_code}/geometry
  3. Assessments - https://api.lightboxre.com/v1/assessments/_on/parcel/us/{lbx_parcel_id}

For additional details regarding each endpoint's request parameters or response models, visit the API Catalog on the LightBox Developer Portal page.

Create variables containing necessary inputs for subsequent calls.

  1. Notice how the API returns any addresses within the buffer distance of the provided geometry, as well as any metadata associated with that address
1# ----------------------------
2# API Usage
3# ----------------------------
4
5# Specify the address to geocode
6address = "24299 Paseo De Valencia, Laguna Woods, CA 92637"
7country_code = "us" # 'us' for the United States
8
9# Geocode the specified address
10address_search_data = geocode_address(lightbox_api_key, address)
11
12# Get the parcel data from the geocoded address
13parcel_data = get_parcel_data_from_address_coordinates(lightbox_api_key, country_code, address_search_data.json()["addresses"][0]["location"]["representativePoint"]["geometry"]["wkt"])
14
15# Get the assessment data from the parcel ID
16assessment_data = get_assessment_data_from_lbx_parcel_id(lightbox_api_key, parcel_data.json()["parcels"][0]["id"])
17
1# Visualize address data in a pandas dataframe format
2pd.json_normalize(address_search_data.json()["addresses"])
1                                                $ref                      id  \
20  https://api.lightboxre.com/v1/addresses/search...  06000B911R4H3YWETLFGHQ   
3
4  uuaid  uaid                                              label  type  \
50  None  None  24299 PASEO DE VALENCIA, LAGUNA WOODS, CA 9263...  None   
6
7  addressConfidenceScore postalCodeDerived corroborationIndex  \
80                   None              None               None   
9
10                                             parcels  ... location.locality  \
110  [{'$ref': 'https://api.lightboxre.com/v1/parce...  ...      LAGUNA WOODS   
12
13  location.regionCode  location.unit  location.county  location.countryCode  \
140                  CA           None    ORANGE COUNTY                    US   
15
16   location.postalCode  location.postalCodeExt  \
170                92637                    3100   
18
19   location.representativePoint.latitude  \
200                              33.609982   
21
22  location.representativePoint.longitude  \
230                            -117.713722   
24
25  location.representativePoint.geometry.wkt  
260              POINT(-117.713722 33.609982)  
27
28[1 rows x 37 columns]
1# Visualize parcel data in a pandas dataframe format
2pd.json_normalize(parcel_data.json()["parcels"])
1                                                $ref                      id  \
20  https://api.lightboxre.com/v1/parcels/us/0202P...  0202P9GBKVNO0LIUTDCJ47   
3
4    fips   parcelApn  county                legalDescription neighborhood  \
50  06059  621-191-16  ORANGE  [N TR 16835 BLK LOT 1 UN HOLD]         None   
6
7   opportunityZone subdivision topography  ...  \
80            False        None       None  ...   
9
10  transaction.lastMarketSale.tdDocumentNumber  \
110                                        None   
12
13  transaction.lastMarketSale.deedTransactionType  \
140                                           None   
15
16  transaction.lastMarketSale.lenderType  \
170                                  None   
18
19  transaction.priorMarketSale.transferDate transaction.priorMarketSale.lender  \
200                                     None                                      
21
22  transaction.multipleApnFlag usplss.township usplss.range usplss.section  \
230                        None            None         None           None   
24
25  usplss.quarter  
260           None  
27
28[1 rows x 113 columns]
1# Visualize assessment data in a pandas dataframe format
2pd.json_normalize(assessment_data.json()["assessments"])
3
1                                                  $ref         apn   fips  \
20    https://api.lightboxre.com/v1/assessments/us/0...  621-191-16  06059   
31    https://api.lightboxre.com/v1/assessments/us/0...  932-810-75  06059   
42    https://api.lightboxre.com/v1/assessments/us/0...  932-810-76  06059   
53    https://api.lightboxre.com/v1/assessments/us/0...  932-810-77  06059   
64    https://api.lightboxre.com/v1/assessments/us/0...  932-810-78  06059   
7..                                                 ...         ...    ...   
8130  https://api.lightboxre.com/v1/assessments/us/0...  932-812-04  06059   
9131  https://api.lightboxre.com/v1/assessments/us/0...  932-812-05  06059   
10132  https://api.lightboxre.com/v1/assessments/us/0...  932-812-06  06059   
11133  https://api.lightboxre.com/v1/assessments/us/0...  932-812-07  06059   
12134  https://api.lightboxre.com/v1/assessments/us/0...  932-812-08  06059   
13
14                         id $metadata alternateApn       avm  \
150    03046JQUZ4Y7Q7TATH24S3      None         None       NaN   
161    03018O7YHXQ8WN8ENIA2R1      None         None  615166.0   
172    030759YM7ZE8HWFQCF0TTH      None         None  459833.0   
183    0303YGY9HW6C14HQCMJFC7      None         None  599500.0   
194    0304XNNLW2WT4VF74Q75N4      None         None  599500.0   
20..                      ...       ...          ...       ...   
21130  03002OKN1NJDVLT53YPMRJ      None         None  566500.0   
22131  0306DPN3Y95BZLE3G29MIC      None         None  566500.0   
23132  03060SKL4MQ53HIX3X1AJT      None         None  373833.0   
24133  0306OVUEJWYCVIZ6WC8HLA      None         None  615166.0   
25134  0300H75ZIL46PZE2QU4MFA      None         None  615166.0   
26
27     improvementPercent  assessedLotSize poolIndicator  ... tax.amount  \
280                   NaN      12353.31191          None  ...        NaN   
291                 49.90              NaN          None  ...     6139.0   
302                 58.04              NaN          None  ...     4099.0   
313                 51.57              NaN          None  ...     5385.0   
324                 51.57              NaN          None  ...     5385.0   
33..                  ...              ...           ...  ...        ...   
34130               52.95              NaN          None  ...     5408.0   
35131               52.95              NaN          None  ...     5408.0   
36132               66.49              NaN          None  ...     3117.0   
37133               49.90              NaN          None  ...     6139.0   
38134               49.90              NaN          None  ...     6139.0   
39
40    tax.rateAreaCode tax.exemption valuationModel.value  \
410             32-010          None                  NaN   
421             32-010          None             692000.0   
432             32-010          None             555000.0   
443             32-010          None             588000.0   
454             32-010          None             588000.0   
46..               ...           ...                  ...   
47130           32-010          None             590000.0   
48131           32-010          None             590000.0   
49132           32-010          None             391000.0   
50133           32-010          None             692000.0   
51134           32-010          None             692000.0   
52
53    valuationModel.valueHigh valuationModel.valueLow valuationModel.date  \
540                        NaN                     NaN                None   
551                   816560.0                567440.0                None   
562                   627150.0                482850.0                None   
573                   699720.0                476280.0                None   
584                   699720.0                476280.0                None   
59..                       ...                     ...                 ...   
60130                 708000.0                472000.0                None   
61131                 708000.0                472000.0                None   
62132                 469200.0                312800.0                None   
63133                 816560.0                567440.0                None   
64134                 816560.0                567440.0                None   
65
66     valuationModel.propensityScore  valuationModel.score  \
670                              None                   NaN   
681                              None                  82.0   
692                              None                  87.0   
703                              None                  81.0   
714                              None                  81.0   
72..                              ...                   ...   
73130                            None                  80.0   
74131                            None                  80.0   
75132                            None                  80.0   
76133                            None                  82.0   
77134                            None                  82.0   
78
79     valuationModel.label  
800                    None  
811                  $692 K  
822                  $555 K  
833                  $588 K  
844                  $588 K  
85..                    ...  
86130                $590 K  
87131                $590 K  
88132                $391 K  
89133                $692 K  
90134                $692 K  
91
92[135 rows x 142 columns]
1# --------------------
2# Print collected data
3# --------------------
4
5# Print the geocoded address data in a readable JSON format
6print(json.dumps(address_search_data.json(), indent=4))
7# Print the parcel data in a readable JSON format
8print(json.dumps(parcel_data.json(), indent=4))
9# Print the assessment data in a readable JSON format
10print(json.dumps(assessment_data.json(), indent=4))
11
12

Commonly Seen Errors

See LightBox Geocoder API for a list of common error responses.

Python Script

View Raw
1import requests
2import json
3from typing import Dict
4
5
6# ----------------------------
7# Function Definitions
8# ----------------------------
9
10# Function to geocode a single address using the LightBox API.
11def geocode_address(lightbox_api_key: str, address: str) -> Dict:
12    """
13    Geocodes the provided address using the LightBox API.
14    
15    Args:
16        lightbox_api_key (str): The API key for accessing the LightBox API.
17        address (str): The address string for matching.
18    
19    Returns:
20        dict: The geocoded address information in JSON format.
21    """
22    # API endpoint configuration
23    BASE_URL = "https://api.lightboxre.com/v1"
24    ENDPOINT = "/addresses/search"
25    URL = BASE_URL + ENDPOINT
26
27    # Setting up request parameters and headers
28    params = {"text": address}
29    headers = {"x-api-key": lightbox_api_key}
30
31    # Sending request to the LightBox API
32    geocoder_data = requests.get(URL, params=params, headers=headers)
33    
34    # Returning the geocoded address information
35    return geocoder_data
36
37
38# Test for the get_parcel_from_lbx_address_id() function
39def get_parcel_data_from_address_coordinates(lightbox_api_key: str, country_code: str, address_wkt_coordinates: str) -> Dict:
40    """
41    Returns a dictionary containing the parcel data for the specified address.
42
43    Args:
44        lightbox_api_key (str): The API key for accessing the LightBox API.
45        country_code (str): The country code for the address.
46        address_wkt_coordinates (str): The address coordinates for the address.
47    """
48
49    # API endpoint configuration
50    BASE_URL = "https://api.lightboxre.com/v1"
51    ENDPOINT = f"/parcels/{country_code}/geometry"
52    URL = BASE_URL + ENDPOINT
53
54    # Setting up request parameters and headers
55    params = {"wkt": address_wkt_coordinates}
56    headers = {"x-api-key": lightbox_api_key}
57
58    # Make the request
59    parcel_data = requests.get(URL, params=params, headers=headers)
60    
61    # Return the parcel data
62    return parcel_data
63
64
65def get_assessment_data_from_lbx_parcel_id(lightbox_api_key: str, parcel_id: str) -> Dict:
66    """
67    Returns a dictionary containing the assessment data for the specified parcel.
68
69    Args:
70        lightbox_api_key (str): The LightBox API key.
71        parcel_id (str): The parcel ID.
72    """
73
74    # API endpoint configuration
75    BASE_URL = "https://api.lightboxre.com/v1"
76    ENDPOINT = f"/assessments/_on/parcel/us/{parcel_id}"
77    URL = BASE_URL + ENDPOINT
78
79    # Setting up request parameters and headers
80    headers = {"x-api-key": lightbox_api_key}
81
82    # Make the request
83    assessment_data = requests.get(URL, headers=headers)
84    
85    # Return the assessment data
86    return assessment_data
87
88
89# Function to test the response status of the geocode_address function.
90def test_geocode_address_response_status(lightbox_api_key: str) -> None:
91    """
92    Tests the response status for various scenarios using the geocode_address function.
93
94    Args:
95        lightbox_api_key (str): The API key for accessing the LightBox API.
96    """
97
98    # Test for a successful request (HTTP status code 200)
99    address = "25482 Buckwood Land Forest, Ca, 92630"
100    address_search_data = geocode_address(lightbox_api_key, address)
101    assert address_search_data.status_code == 200, f"Expected status code 200, but got {address_search_data.status_code}"
102
103    # Test for an unsuccessful request due to an empty address (HTTP status code 400)
104    address = ""  # No address specified
105    address_search_data = geocode_address(lightbox_api_key, address)
106    assert address_search_data.status_code == 400, f"Expected status code 400, but got {address_search_data.status_code}"
107
108    # Test for an unsuccessful request due to an invalid API key (HTTP status code 401)
109    address = "25482 Buckwood Land Forest, Ca, 92630"
110    address_search_data = geocode_address("My-LightBox-Key", address)  # Invalid API key
111    assert address_search_data.status_code == 401, f"Expected status code 401, but got {address_search_data.status_code}"
112
113    # Test for an unsuccessful request due to an incomplete address (HTTP status code 404)
114    address = "25482 Buckwood Land Forest"  # Incomplete address
115    address_search_data = geocode_address(lightbox_api_key, address)
116    assert address_search_data.status_code == 404, f"Expected status code 404, but got {address_search_data.status_code}"
117
118
119# Test the get_parcel_data_from_address_coordinates function
120def test_get_parcel_data_from_address_coordinates(lightbox_api_key):
121    """
122    Test the get_parcel_data_from_address_coordinates function
123    
124    Args:
125        lightbox_api_key (str): The LightBox API key
126    """
127
128    # Test for a successful request (HTTP status code 200)
129    address = "25482 Buckwood Land Forest, Ca, 92630"
130    country_code = "us"
131    address_search_data = geocode_address(lightbox_api_key, address)
132    address_coordinates = address_search_data.json()["addresses"][0]["location"]["representativePoint"]["geometry"]["wkt"]
133    parcel_data = get_parcel_data_from_address_coordinates(lightbox_api_key, country_code, address_coordinates)
134    assert parcel_data.status_code == 200, f"Expected status code 200, but got {parcel_data.status_code}"
135
136    # Test for an unsuccessful request due to an invalid address ID (HTTP status code 400)
137    address_coordinates = "foobar"
138    parcel_data = get_parcel_data_from_address_coordinates(lightbox_api_key, country_code, address_coordinates)
139    assert parcel_data.status_code == 400, f"Expected status code 400, but got {parcel_data.status_code}"
140
141    # Test for an unsuccessful request due to an invalid API key (HTTP status code 401)
142    parcel_data = get_parcel_data_from_address_coordinates(lightbox_api_key+"foobar", country_code, address_coordinates)
143    assert parcel_data.status_code == 401, f"Expected status code 401, but got {parcel_data.status_code}"
144
145
146# Test the get_parcel_data_from_lbx_parcel_id function
147def test_get_assessment_data_from_lbx_parcel_id(lightbox_api_key):
148    """
149    Test the get_assessment_data_from_lbx_parcel_id function
150    
151    Args:
152        lightbox_api_key (str): The LightBox API key
153    """
154
155    # Test for a successful request (HTTP status code 200)
156    address = "25482 Buckwood Land Forest, Ca, 92630"
157    country_code = "us"
158    address_search_data = geocode_address(lightbox_api_key, address)
159    address_coordinates = address_search_data.json()["addresses"][0]["location"]["representativePoint"]["geometry"]["wkt"]
160    parcel_data = get_parcel_data_from_address_coordinates(lightbox_api_key, country_code, address_coordinates)
161    parcel_id = parcel_data.json()["parcels"][0]["id"]
162    assessment_data = get_assessment_data_from_lbx_parcel_id(lightbox_api_key, parcel_id)
163    assert assessment_data.status_code == 200, f"Expected status code 200, but got {assessment_data.status_code}"
164
165    # Test for an unsuccessful request due to an invalid parcel ID (HTTP status code 400)
166    parcel_id = "1234567890"
167    assessment_data = get_assessment_data_from_lbx_parcel_id(lightbox_api_key, parcel_id)
168    assert assessment_data.status_code == 400, f"Expected status code 400, but got {assessment_data.status_code}"
169
170    # Test for an unsuccessful request (HTTP status code 401)
171    assessment_data = get_assessment_data_from_lbx_parcel_id(lightbox_api_key+"foobar", parcel_id)
172    assert assessment_data.status_code == 401, f"Expected status code 401, but got {assessment_data.status_code}"
173
174
175# ----------------------------
176# API Usage
177# ----------------------------
178
179# Assign your LightBox API key
180lightbox_api_key = ""
181
182# Specify the address to geocode
183address = "24299 Paseo De Valencia, Laguna Woods, CA 92637"
184country_code = "us" # 'us' for the United States
185
186# Geocode the specified address
187address_search_data = geocode_address(lightbox_api_key, address)
188
189# Get the parcel data from the geocoded address
190parcel_data = get_parcel_data_from_address_coordinates(lightbox_api_key, country_code, address_search_data.json()["addresses"][0]["location"]["representativePoint"]["geometry"]["wkt"])
191
192# Get the assessment data from the parcel ID
193assessment_data = get_assessment_data_from_lbx_parcel_id(lightbox_api_key, parcel_data.json()["parcels"][0]["id"])
194
195
196# --------------------
197# Print collected data
198# --------------------
199
200# Print the geocoded address data in a readable JSON format
201print(json.dumps(address_search_data.json(), indent=4))
202# Print the parcel data in a readable JSON format
203print(json.dumps(parcel_data.json(), indent=4))
204# Print the assessment data in a readable JSON format
205print(json.dumps(assessment_data.json(), indent=4))
206
207
208# ----------------------------
209# API Testing
210# ----------------------------
211
212# Perform tests to verify the response status of the geocode_address function
213test_geocode_address_response_status(lightbox_api_key)
214test_get_parcel_data_from_address_coordinates(lightbox_api_key)
215test_get_assessment_data_from_lbx_parcel_id(lightbox_api_key)
216
217