DROP Process to IRM — API Integration Guide

Overview

Document Type: API Integration Guide  ·  Audience: Data Broker System Developers  ·  Version: 2.0  ·  Last updated: 2026-05-29

This guide describes the integration between the DROP Portal and the IRM (Identity and Request Management) system for processing Data Subject deletion requests. It covers the API operations a Data Broker system performs to ingest, tag, close, and report on DROP-sourced requests.

This document focuses on the three steps that require direct API integration: creating a request in IRM (Step 4), closing it after deletion (Step 6), and polling for closed requests to report back to the DROP Portal (Step 7).

Process Flow
Step System Action
1 DROP Portal Data Subject submits a deletion request through the DROP Portal.
2 Data Broker Downloads the deletion list periodically.
3 Data Broker Prepares the payload for IRM ingestion.
4 ★ Data Broker → IRM Creates the request in IRM and applies a label to tag it as DROP-sourced.
5 IRM Request is created; associated tasks are generated per task-template configuration.
6 ★ Data Broker → IRM Performs deletion in its own system and closes the IRM request.
7 ★ Data Broker → IRM Polls IRM for closed DROP-labeled requests and reports completion back to the DROP Portal.

★ Steps covered in this guide.

📋 Note on identity verification: Verification behavior is governed by the form a request is created against (formId) and your account configuration — there is no per-request bypass flag. To skip end-user email verification for DROP batches, set verifyEmail=false when creating the request and/or use a dedicated DROP intake form.
Base URL & Authentication

All endpoints use the IRM application base path /api/v1 on your deployed IRM host. Every request requires the following headers:

Authorization: Bearer <access_token>
Content-Type: application/json
Accept: application/json
📋 Notes

Access tokens are short-lived. Implement token refresh logic before expiry and treat a 401 response as a signal to re-authenticate.

Contact your IRM account administrator to obtain client credentials and to enable external API access for the integration user.

Step 4.1 — Discover the Form and Field IDs

Requests are created against a specific form, and the request body is keyed by that form's field IDs — not display labels. Always discover the form and its fields first, then build your create payload from those IDs.

⚠️ Important: Field IDs vary per form. Always read the actual IDs from the form response rather than hard-coding them.
List Available Forms
GET /api/v1/external/forms/all
Authorization: Bearer <access_token>
Accept: application/json

Optional query parameters: name, statuses, brandName, brandIds.

Sample response:

[
  {
    "id": "8c2a1f3e-1111-4aaa-9bbb-1234567890ab",
    "name": "DROP Deletion Intake",
    "status": "PUBLISHED",
    "brandName": "Acme"
  }
]

Use the id of the appropriate form as your formId in subsequent calls.

Get Form Fields
GET /api/v1/external/requests?formId={formId}
Authorization: Bearer <access_token>
Accept: application/json

Optional query parameter: locale.

Sample response:

{
  "name": "DROP Deletion Intake",
  "fields": [
    { "id": "00000000-0000-0000-0000-00000000100a", "display": "First Name",    "type": "string", "dataType": "text",   "required": true,  "values": [] },
    { "id": "00000000-0000-0000-0000-00000000100b", "display": "Last Name",     "type": "string", "dataType": "text",   "required": true,  "values": [] },
    { "id": "00000000-0000-0000-0000-000000001003", "display": "Email",         "type": "string", "dataType": "email",  "required": true,  "values": [] },
    { "id": "00000000-0000-0000-0000-000000001004", "display": "Country",       "type": "string", "dataType": "select", "required": false,
      "values": [
        { "id": "PH", "display": "Philippines"    },
        { "id": "US", "display": "United States"  }
      ]
    },
    { "id": "7c9e6a1b-3d2f-4a5e-8b10-2f6c4d8a1e90", "display": "Account Number", "type": "string", "dataType": "text", "required": false, "values": [] }
  ]
}
📋 How to use these field IDs
Field IDs are UUIDs. Use the id values — not display labels — as keys in your create payload.
Standard IRM form fields use reserved IDs (e.g. email ...1003, country ...1004, first/last name ...100a/...100b). Custom fields use generated UUIDs.
For dropdown fields (those with a values list), submit the option's id — not the display label. For example, submit "PH", not "Philippines".
Provide a value for every field where required is true.
Step 4.2 — Create the IRM Request

Create the request against the form discovered in the previous step.

POST /api/v1/external/requests?formId={formId}&verifyEmail=false
Authorization: Bearer <access_token>
Content-Type: application/json
Query Parameters
Parameter Required Description
formId Yes The form ID from Step 4.1. Defines the request type, data-subject type, and valid fields.
verifyEmail No Defaults true. Set false to skip email verification for DROP-sourced batches.
locale No Locale for the request. Defaults to the form's default locale.
sourceWebsite No Origin website string for provenance tracking.
ipAddress No Originating IP address for provenance tracking.
Request Body

A flat map of form field UUID → value, using the field IDs read in Step 4.1:

{
  "00000000-0000-0000-0000-00000000100a": "Juan",
  "00000000-0000-0000-0000-00000000100b": "Dela Cruz",
  "00000000-0000-0000-0000-000000001003": "juan.delacruz@email.com",
  "00000000-0000-0000-0000-000000001004": "PH",
  "7c9e6a1b-3d2f-4a5e-8b10-2f6c4d8a1e90": "ACME-99231"
}
Response
{
  "seqId": "seq_001",
  "resultType": "REQUEST_CREATED",
  "message": "Request created successfully.",
  "result": {
    "id": "3f1c0a9e-7b2d-4c5a-9f10-2a8e6d4b1c77",
    "status": "UNVERIFIED",
    "...": "full request object"
  }
}
📋 Note:resultType is REQUEST_CREATED on success or REQUEST_FAILED on a validation error (details in message). The request id is a UUID — retain it for the label and close calls.
Step 4.4 — Apply the DROP Label

Labels are tags identified by name. Apply the DROP label to the request you just created by addressing the label by name in the path. No request body is needed.

PUT /api/v1/external/requests/{requestId}/labels/name/{labelName}
Authorization: Bearer <access_token>
Path Parameter Required Description
requestId Yes The request UUID returned from Step 4.2.
labelName Yes The label to add. Use DROP for DROP-sourced requests.

Sample request:

PUT /api/v1/external/requests/3f1c0a9e-7b2d-4c5a-9f10-2a8e6d4b1c77/labels/name/DROP

Response — the applied label:

{ "id": "9f8e7d6c-...", "name": "DROP" }
📋 Note: If the DROP label does not yet exist for the account, it is created automatically on first use. A label has a name only — there is no category, applied-by, or metadata field.
Read or Remove Labels
# List labels on a request
GET /api/v1/external/requests/{id}/labels

# Remove a label
DELETE /api/v1/external/requests/{requestId}/labels/name/{labelName}

GET response:

{ "labels": [ { "id": "9f8e7d6c-...", "name": "DROP" } ] }
Step 6 — Close the IRM Request
📋 Note: Closing is an explicit action. There is no generic "update request" call.
POST /api/v1/external/requests/{id}/close
Authorization: Bearer <access_token>
Content-Type: application/json
Request Body
{
  "status": "ACCEPT",
  "sendEmail": false,
  "rejectReason": null,
  "noEmailReason": "Closed by Data Broker after deletion."
}
Field Required Description
status Yes ACCEPT to approve the deletion or REJECT to deny it.
sendEmail No Whether to send a closure notification to the data subject. Defaults true; set false for DROP batch closures.
rejectReason Conditional Required when status is REJECT.
noEmailReason Conditional Required when sendEmail is false.
emailTemplate No Optional template configuration for the closure email.

The response returns the updated request object. Internally, ACCEPT resolves to CLOSED_ACCEPTED or CLOSED_ACCEPTED_NO_EMAIL, and REJECT to CLOSED_REJECTED or CLOSED_REJECTED_NO_EMAIL, depending on sendEmail. See the Status Lifecycle below.

Status Lifecycle

There is no single "closed" status. Several closed-state values exist:

UNVERIFIED ──(verify)──► IN_PROGRESS ──(close)──► CLOSED_ACCEPTED
                                                   CLOSED_REJECTED
                                                   CLOSED_ACCEPTED_NO_EMAIL
                                                   CLOSED_REJECTED_NO_EMAIL
                                                   CLOSED_EXPIRED
                                                   CLOSED_ID_FAILED
                                                   CLOSED_LIMIT_EXCEEDED
                                                   ...
📋 Notes

New form-created requests typically start at UNVERIFIED. Use verifyEmail=false to bypass the email verification step for DROP batches.

When filtering for "closed" requests, filter by the specific closed-state values you care about rather than a generic closed flag.

The full list of valid status values is available at GET /api/v1/external/requests/statuses.

Step 7 — Retrieve Closed DROP Requests

Search for requests using a JSON filter body. Results are returned as a paginated response.

POST /api/v1/external/requests/search?page=0&size=100&sort=createdDate,desc
Authorization: Bearer <access_token>
Content-Type: application/json
Accept: application/json
Pagination Parameters
Parameter Description
page 0-based page index. Defaults to 0.
size Page size. Defaults to 25.
sort Sort expression, e.g. createdDate,desc.
Request Body — Filter
{
  "labelNames": ["DROP"],
  "statuses": ["CLOSED_ACCEPTED", "CLOSED_REJECTED"],
  "fromModifiedDate": "2026-05-01T00:00:00Z"
}
Field Type Description
labelNames string set Filter by label name(s). Use ["DROP"].
statuses enum set One or more status values. Typically one or more closed states — see Status Lifecycle.
fromModifiedDate / toModifiedDate ISO-8601 Modified-date range. Use fromModifiedDate as an incremental cursor ("changed since last poll").
fromCreatedDate / toCreatedDate ISO-8601 Created-date range.
fromDueDate / toDueDate ISO-8601 Due-date range.
email, name, ids, formIds, requestTypeIds, dataSubjectTypeIds Additional optional filters.
notLabelNames / notLabelIds set Exclude requests carrying these labels.
Response (Paginated)
{
  "content": [
    {
      "id": "3f1c0a9e-7b2d-4c5a-9f10-2a8e6d4b1c77",
      "status": "CLOSED_ACCEPTED",
      "...": "request fields"
    }
  ],
  "pageable": { "pageNumber": 0, "pageSize": 100 },
  "totalElements": 2,
  "totalPages": 1,
  "first": true,
  "last": true,
  "numberOfElements": 2
}
Integration Notes & Best Practices
Recommended Sequence (Step 4)
1. GET  /api/v1/external/forms/all                              → find DROP formId
2. GET  /api/v1/external/requests?formId=...                    → read field IDs

For each deletion_request in batch:
3. POST /api/v1/external/requests?formId=...&verifyEmail=false  → obtain request UUID
4. PUT  /api/v1/external/requests/{id}/labels/name/DROP         → apply DROP label
5. Persist { drop_request_id, irm_request_uuid } locally for polling/reporting
Polling Strategy (Step 7)
Poll POST /api/v1/external/requests/search with { "labelNames": ["DROP"], "statuses": ["CLOSED_ACCEPTED", ...] }.
Use fromModifiedDate to fetch only incremental changes. Persist the last successful timestamp locally between polls.
Iterate all pages (using last / totalPages) before reporting back to the DROP Portal.
Auth & Retry Handling
Refresh the Bearer token before expiry. Treat a 401 response as a signal to re-authenticate.
Deduplicate on your own drop_request_id before issuing a create call to avoid creating duplicate requests on retry.
On 5xx errors, retry with exponential backoff.
Access Checklist
Operation Access Required
List forms / read form fields Form view access + external API access
Create request Create-request access on the form + external API access
Apply / remove labels Label-update access on the request + external API access
Close request Close/complete access on the request + external API access
Poll requests Request view access on the account + external API access
TrustArc  ·  DROP Process to IRM — API Integration Guide  ·  support.trustarc.com v2.0  ·  2026-05-29