API Reference
This article covers the API endpoints used between your systems and DataGrail for Data Broker Compliance. There are three deletion dispatch patterns — implement whichever matches your infrastructure. All three patterns share the same authentication summary and error codes documented at the end of this article.
Before implementing a dispatch pattern, ensure you have:
- Completed the Quickstart and chosen your dispatch method
- Completed Identifier Configuration and selected your DROP list types
- Completed Ingestion Format and begun delivering consumer identifiers to DataGrail
Webhook
DataGrail POSTs to a URL you configure when a DROP match occurs.
Deletion Dispatch (DataGrail → You)
POST <your-webhook-url>
Content-Type: application/json
X-Datagrail-Event: drop.deletion
X-Webhook-Timestamp: 1717027200
X-Webhook-Signature: v1=<base64(HMAC-SHA256(shared_secret, "<timestamp>:<body>"))>
Request body:
{
"schema_version": "1.0",
"event": "drop.deletion",
"ticket_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"broker_id": "4821",
"drop_session_id": "f0e1d2c3-b4a5-6789-0fed-cba987654321",
"hash_type": "email",
"match_date": "2026-05-30",
"remote_identifier": "0035f00000A1B2CAAZ",
"remote_identifier_kind": "external_id",
"callback_url": "https://yourcompany.datagrail.io/api/v2/webhooks/callback"
}
Fields:
| Field | Description |
|---|---|
event | Always "drop.deletion" — distinguishes from DSR webhooks |
ticket_uuid | DataGrail's internal tracking ID for this deletion |
broker_id | Your CalPrivacy data broker registration number |
drop_session_id | The specific DROP session/cycle this match came from |
hash_type | Which list type matched: email, phone, ndz, name_vin, maid, ctvid |
remote_identifier | Your consumer pointer — the same value you sent during ingestion |
remote_identifier_kind | How to interpret the pointer: external_id, row_uuid, email, phone |
callback_url | URL to POST your outcome to when deletion is complete |
Return 2xx to acknowledge receipt. Process the deletion asynchronously.
Signature verification: Compute HMAC-SHA256(shared_secret, "<X-Webhook-Timestamp>:<raw-body>"), Base64-encode, and compare to the value after v1= in X-Webhook-Signature.
Deletion Outcome Callback (You → DataGrail)
After processing the deletion, POST the outcome to the callback_url provided in the webhook. Use ticket_uuid from the original request to correlate the callback.
POST <callback_url>
Content-Type: application/json
Authorization: Bearer <your-datagrail-api-token>
{
"schema_version": "1.0",
"status": "completed",
"ticket_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"drop_outcome": "deleted",
"completed_at": "2026-05-30T18:45:00Z",
"failure_reason": null
}
drop_outcome values:
| Value | DROP Status Code | Meaning |
|---|---|---|
deleted | 3 | Consumer's data was deleted |
not_found | 5 | Consumer not found in your system |
opted_out | 4 | Consumer previously opted out |
failed | — | Deletion failed (provide failure_reason) |
Polling
Your agent pulls pending DROP deletion work items from DataGrail on a schedule.
Retrieve Pending Deletions (You → DataGrail)
GET /api/v2/internal_systems/pending_work?connector_type=drop&broker_registration_id=<uuid>&limit=100
Authorization: Bearer <agent-api-token>
Response:
{
"work_items": [
{
"operation": "drop_delete",
"ticket_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"connection_uuid": "c1d2e3f4-a5b6-7890-cdef-123456789abc",
"broker_id": "4821",
"drop_session_id": "f0e1d2c3-b4a5-6789-0fed-cba987654321",
"hash_type": "email",
"match_date": "2026-05-30",
"remote_identifier": "0035f00000A1B2CAAZ",
"remote_identifier_kind": "external_id",
"results_token": "a1b2c3d4e5f67890",
"callback_url": "https://yourcompany.datagrail.io/api/v2/internal_systems/request_callback",
"created_at": "2026-05-30T14:00:00Z"
}
],
"has_more": false,
"poll_after": "2026-05-30T15:00:00Z"
}
- Each work item is leased for 24 hours. If you don't confirm the outcome within 24h, it becomes available again.
poll_afteris a hint for when the next poll would be productive — respect it to avoid rate limiting.- Process each item and POST the outcome to
callback_urlusing the same callback format as the webhook pattern above (includeresults_tokeninstead ofticket_uuidfor polling callbacks).
ISI (Internal Systems Integration)
ISI is a customer-hosted REST API that DataGrail calls into. DROP adds two new endpoints to the existing ISI spec.
Prerequisites
Your ISI API must:
- Serve over HTTPS with TLS 1.2+
- Authenticate via OAuth 2.0 Client Credentials or static bearer token
- Advertise DROP capabilities in
/api/v1/connections/list:
{
"results": [
{
"uuid": "c1d2e3f4-a5b6-7890-cdef-123456789abc",
"capabilities": [
"privacy/access",
"privacy/delete",
"privacy/drop/identifiers",
"privacy/drop/delete"
]
}
]
}
DROP Delete Endpoint
DataGrail calls this when a DROP match occurs and your system needs to perform the deletion.
POST /api/v1/privacy/drop/delete/<connection-uuid>
Authorization: Bearer <token>
Content-Type: application/json
Request body:
{
"request_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"results_token": "a1b2c3d4e5f67890",
"callback_path": "/api/v2/internal_systems/request_callback",
"drop_context": {
"broker_id": "4821",
"drop_session_id": "f0e1d2c3-b4a5-6789-0fed-cba987654321",
"hash_type": "email",
"match_date": "2026-05-30"
},
"remote_identifier": "0035f00000A1B2CAAZ",
"remote_identifier_kind": "external_id"
}
Your immediate response:
HTTP/1.1 200 OK
{"status": "processing"}
Your callback when deletion completes:
{
"status": "completed",
"results_token": "a1b2c3d4e5f67890",
"drop_outcome": "deleted",
"completed_at": "2026-05-30T18:45:00Z"
}
DROP deletions have different requirements than standard DSR deletions — different regulatory timelines, audit trails, and customer-side workflows. A separate endpoint ensures you can implement DROP-specific handling without affecting your DSR pipeline.
DROP Identifier Retrieval Endpoint
DataGrail calls this to retrieve clear identifiers for a matched consumer so it can issue deletions to 3rd-party SaaS systems (Salesforce, HubSpot, etc.) on your behalf.
POST /api/v2/privacy/drop/identifiers/<connection-uuid>
Authorization: Bearer <token>
Content-Type: application/json
Request body:
{
"request_uuid": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"remote_identifier": "0035f00000A1B2CAAZ",
"remote_identifier_kind": "external_id",
"identifier_categories": ["email", "phone"]
}
Your synchronous response:
HTTP/1.1 200 OK
{
"identifiers": {
"email": [{"email": "alice@example.com"}, {"email": "alice.work@example.com"}],
"phone": [{"phone": "+15551234567"}]
}
}
Only after a DROP match, and only if you have 3rd-party SaaS connections configured in DataGrail that require clear identifiers to process deletions. If you only need internal deletions handled by the DELETE endpoint above, this endpoint is not required.
Authentication Summary
The following table summarizes the authentication method for each dispatch pattern:
| Pattern | Auth Method |
|---|---|
| Webhook (DataGrail → you) | HMAC-SHA256 signature on each request |
| Webhook callback (you → DataGrail) | Bearer token (provided by DataGrail) |
| Polling (you → DataGrail) | Bearer token (agent API key) |
| ISI (DataGrail → you) | OAuth 2.0 Client Credentials or static bearer token |
Error Codes
The following HTTP status codes may be returned by DataGrail endpoints:
| Code | Meaning |
|---|---|
200 | Success |
202 | Accepted (async processing started) |
400 | Bad request — check response body for validation details |
401 | Authentication failed |
403 | Insufficient permissions |
404 | Resource not found |
409 | Conflict (e.g., duplicate upload in progress) |
429 | Rate limited — respect Retry-After header |
500 | Internal server error |
Error response body:
{
"error": "validation_failed",
"message": "schema_version '2.0' is not supported",
"supported_versions": ["1.0"]
}
Disclaimer: The information contained in this message does not constitute as legal advice. We would advise seeking professional counsel before acting on or interpreting any material.