California DROP Technical Reference

DROP API Specificationfor Data Brokers

We put this reference together to help data brokers understand the DROP API.

How DROP Works

The DROP Data Broker API enables data brokers to integrate with California's Delete Request and Opt-out Platform to programmatically retrieve consumer deletion request data and report status updates.

1

Download

Retrieve a ZIP archive of CSV files containing hashed consumer identifiers for each data list enabled on your API key.

2

Process

Match hashed identifiers against your records and take the required action: delete, opt out, exempt, or mark as not found.

3

Upload

Submit a CSV response file reporting the status code for each work item back to the DROP platform.

Want a simpler integration?

Superset handles the full DROP pipeline from download through identity matching to status reporting. If you'd rather not build it yourself, we can help.

See how our DROP integration works

Authentication

All requests require an API key passed in the X-API-KEY header. API keys are generated in the Data Broker Portal after registration and fee payment are complete.

Header
X-API-KEY: your-api-key-here

Servers & Maintenance Window

EnvironmentBase URL
Productionhttps://api.drop.privacy.ca.gov
Sandboxhttps://api.drop.privacy.ca.gov/sandbox

Daily Maintenance Window

Push and pull requests are closed between 1:00 AM to 3:00 AM Pacific Time daily while the platform batches the most current data. Requests during this window may return errors and should be retried afterward.

Normalization & Hashing

All identifiers are hashed with SHA-256 using UTF-8 input encoding. The output is Base64. The following canonicalization rules are applied before hashing. These rules are normative for interoperability with the sandbox CSV files and submission summary reports.

Canonicalization Rules

FieldRule
EmailRemove all whitespace, then lowercase.
DOBFormat as YYYYMMDD with no separators.
PhoneKeep digits only, then retain the last 10 digits.
ZIPKeep alphanumeric characters only, lowercase, truncate to the first 5 characters, then remove leading zeros.
NamesTransliterate to ASCII, lowercase, then remove spaces, punctuation, separators, and any remaining non-alphanumeric characters.Lily-Anne → lilyanne, D’Amico → damico, Ella Jane → ellajane, Nguyễn → nguyen, Михаил → mikhail
MAIDLowercase, then remove hyphens and any other non-alphanumeric characters.
VINLowercase, then remove any non-alphanumeric characters.
CTVIDLowercase, then remove punctuation and separators such as _, -, and :.

Names are normalized per field (first name and last name independently) before any list-specific concatenation workflow.

NDZ and NVIN Concatenated Hashes

For concatenated list types, each normalized field is hashed independently to Base64. Those Base64 digests are concatenated with no separator, then the concatenated UTF-8 string is hashed again and Base64-encoded to produce the final digest.

NDZ

firstName + lastName + dob + zip

NVIN

firstName + lastName + vin

Reference Implementation

C#
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

static string ComputeSha256Base64(string canonical)
{
    using var sha = SHA256.Create();
    var hashBytes = sha.ComputeHash(Encoding.UTF8.GetBytes(canonical));
    return Convert.ToBase64String(hashBytes);
}

static string NormalizeEmail(string input)
    => Regex.Replace(input ?? "", @"\s+", "").ToLowerInvariant();

static string NormalizePhone(string inputNumber)
{
    var digits = new string((inputNumber ?? "").Where(char.IsDigit).ToArray());
    return digits.Length > 10 ? digits[^10..] : digits;
}

static string NormalizeZip(string input)
{
    var cleaned = new string((input ?? "").Where(char.IsLetterOrDigit).ToArray()).ToLowerInvariant();
    var truncated = cleaned.Length <= 5 ? cleaned : cleaned[..5];
    return truncated.TrimStart('0');
}
GET/data/download

Download consumer deletion request data

Returns a ZIP archive containing one CSV file per consumer data list enabled for the authenticated API key.

CSV File Naming Convention

<YYYYMMDD>_<DataBrokerId>_<DataType>.csv

Filename capitalization is not significant. Preserve the exact file name when uploading your response.

CSV Schemas by List Type

List TypeColumns
NDZId, Hash
EMAILId, Hash
PHONEId, Hash
MAIDId, Hash
NVINId, Hash
CTVIDId, Hash

Example Downloaded CSV

CSV
Id,Hash
679,KA18MT/ph6IHYjzT9zwETySDQyvSh87YuoSBpOQtkhE=

Responses

200 ZIP archive containing CSV files for each enabled consumer data list.
401 API key missing or invalid.
403 Access denied; payment not completed.
404 Endpoint does not exist.
429 Rate limit exceeded.
500 Internal server error or maintenance window.

Code Samples

curl
curl -X GET "https://api.drop.privacy.ca.gov/data/download" \
  -H "accept: */*" \
  -H "X-API-KEY: your-api-key-here" \
  --output download.zip
PowerShell
$headers = @{
  "X-API-KEY" = "your-api-key-here"
  "Accept" = "text/zip"
}
Invoke-WebRequest \
  -Uri "https://api.drop.privacy.ca.gov/data/download" \
  -Headers $headers \
  -OutFile "download.zip"
POST/data/upload

Upload new status response file

Upload a CSV response file for the first time for a given downloaded file. One or more CSV response files may be uploaded in the same request.

CSV Requirements

  • Use the header Id,Status
  • Use the original downloaded file name, optionally with an added suffix before .csv
  • Optional suffix of up to 10 characters when needed to distinguish repeated uploads for the same base file name
  • Contain valid status codes (2, 3, 4, or 5) for each work item ID
  • Upload as CSV files, not a ZIP archive

Valid File Name Examples

20260312_4821_Email.csv20260312_4821_Email_part01.csv

Request Body

Files are sent as multipart/form-data with the field name files.

Example Upload CSV

CSV
Id,Status
679,2
680,5

Responses

200 Upload processed. Check acceptedCount and rejectedCount to determine outcome.
400 Invalid parameters, formatting, or CSV columns.
401 API key missing or invalid.
403 Access denied; payment not completed.
404 Endpoint does not exist.
429 Rate limit exceeded.
500 Internal server error or maintenance window.

Code Samples

curl
curl -X POST "https://api.drop.privacy.ca.gov/data/upload" \
  -H "accept: */*" \
  -H "X-API-KEY: your-api-key-here" \
  -H "Content-Type: multipart/form-data" \
  -F "files=@20260312_4821_Email.csv;type=text/csv"
JavaScript
const formData = new FormData();
formData.append('files', fileBlob, '20260312_4821_Email.csv');

const response = await fetch(
  'https://api.drop.privacy.ca.gov/data/upload',
  {
    method: 'POST',
    headers: {
      'X-API-KEY': 'your-api-key-here'
    },
    body: formData
  }
);

const result = await response.json();
POST/data/amend

Amend a previously uploaded status response file

Upload a corrected CSV response file for a previously submitted download. One or more corrected CSV response files may be uploaded in the same request. The request format is identical to /data/upload. Use this endpoint when you need to update statuses in a file that was already accepted via /data/upload.

Responses

200 Amendment processed. Check acceptedCount and rejectedCount to determine outcome.
400 Invalid parameters, formatting, or CSV columns.
401 API key missing or invalid.
403 Access denied; payment not completed.
404 Endpoint does not exist.
429 Rate limit exceeded.
500 Internal server error or maintenance window.

Code Sample

curl
curl -X POST "https://api.drop.privacy.ca.gov/data/amend" \
  -H "accept: */*" \
  -H "X-API-KEY: your-api-key-here" \
  -H "Content-Type: multipart/form-data" \
  -F "files=@20260312_4821_Email.csv;type=text/csv"

Schemas & Status Codes

Status Codes

Status codes reported for each work item in the uploaded CSV.

CodeLabelDescription
2ExemptedMatch found, data exempt under Civil Code §1798.99.86(c)(2).
3DeletedMatch found, non-exempt personal information deleted.
4Opted outMultiple consumers linked, all opted out of sale or sharing.
5Not foundNo match after matching process.

UploadResponse

Response returned after a file upload (new or amend).

PropertyTypeDescription
mode"new" | "amend"The upload mode: new for first submission, amend for corrections.
acceptedCountintegerNumber of files accepted in this request.
rejectedCountintegerNumber of files rejected in this request.
acceptedFileResult[]List of accepted files with confirmation messages.
rejectedFileResult[]List of rejected files with error messages.

FileResult

Result for a single file in an upload response.

PropertyTypeDescription
fileNamestringThe name of the uploaded CSV file. Must be the original downloaded file name or that name plus an optional suffix of up to 10 characters before .csv.
messagestringHuman-readable result message.

CSV Row Formats

Downloaded CSV

ColumnType
Idinteger
Hashstring (SHA-256 Base64)

Upload CSV

ColumnType
Idinteger
StatusStatusCode (2, 3, 4, or 5)

List Types

Consumer data list types enabled for the API key. These values match the live sandbox file suffixes.

NDZEMAILPHONEMAIDNVINCTVID

Example Responses

Accepted new upload

JSON
{
  "mode": "new",
  "acceptedCount": 1,
  "rejectedCount": 0,
  "accepted": [
    {
      "fileName": "20260312_4821_Email.csv",
      "message": "Accepted. NEW file queued for processing."
    }
  ],
  "rejected": []
}

Rejected: invalid CSV header

JSON
{
  "mode": "new",
  "acceptedCount": 0,
  "rejectedCount": 1,
  "accepted": [],
  "rejected": [
    {
      "fileName": "20260312_4821_Email.csv",
      "message": "Invalid CSV header. Expected: Id,Status"
    }
  ]
}

Rejected: duplicate file

JSON
{
  "mode": "new",
  "acceptedCount": 0,
  "rejectedCount": 1,
  "accepted": [],
  "rejected": [
    {
      "fileName": "20260312_4821_Email.csv",
      "message": "You already uploaded a file with the same filename for this run."
    }
  ]
}

Accepted amended upload

JSON
{
  "mode": "amend",
  "acceptedCount": 1,
  "rejectedCount": 0,
  "accepted": [
    {
      "fileName": "20260312_4821_Email.csv",
      "message": "Accepted. AMEND file queued for processing."
    }
  ],
  "rejected": []
}

Error Responses

All endpoints share the same error response codes.

StatusMeaningAction
400Bad RequestInvalid parameters, file formatting, file name, or CSV columns. Correct the request before retrying.
401UnauthorizedAPI key is missing or invalid. Generate a new key from the Data Broker Portal.
403ForbiddenAccess denied. This typically means payment has not been completed through the Data Broker Portal.
404Not FoundThe requested endpoint does not exist. Verify the API URL.
429Too Many RequestsRate limit exceeded. Rate limits are adjusted automatically based on system load. Back off and retry after a delay.
500Server ErrorInternal server error. This may occur during the daily maintenance window (1:00 AM to 3:00 AM Pacific Time) or due to a transient issue. Retry later.

Questions about DROP integration?

If you have questions about the DROP API, the hashing workflow, or how to operationalize your integration, reach out to us. Superset has already built a complete DROP pipeline for data brokers and we handle download, identity matching, and status reporting so you don't have to.