Last date modified: 2026-May-21
Collect API
The Collect API allows you to:
- Create collection jobs in RelativityOne.
-
Generate and validate targets (e.g., custodians and groups).
- Start and stop collection runs.
- Monitor job status and metrics.
- Receive webhook events as jobs progress.
A collection job represents an eDiscovery collection from a specific data source, ex: Microsoft 365, into a RelativityOne workspace.
Guidelines for the Collect API
Review the following guidelines for working with this API.
URLs
- The URLs for REST endpoints contain path parameters that you need to set before making a call:
- Set the {versionNumber} placeholder to the version of the REST API that you want to use, using the format lowercase v and the version number, for example v1.
- Set other path parameters in the URLs to the Artifact ID of a given entity, for example setting {workspaceID} to the Artifact ID of a workspace.
To indicate the admin-level context, set the {workspaceID} path parameter to -1. - Ensure that the X-CSRF-Header is set.
- If applicable, for more information on the retrieving the Artifact ID, see Relativity artifact identifiers.
For example, you can use the following URL to stop a collection job:
1
https://api.relativityone.tld/v1/CollectAPI/{workspaceArtifactId}/collection/{collectionArtifactId}/stop
Set the path parameters as follows:
- {versionNumber} to the version of the service, such as v1.
- workspaceId / workspaceArtifactId – integer identifier of the Relativity workspace.
workspaceId and workspaceArtifactId both refer to the workspace artifact ID.
- collectionArtifactId – integer identifier of the collection job artifact.
Authentication & Authorization
The following section describes the authentication and authorization.
Authentication
The API uses OAuth 2.0 Client Credentials against Azure AD.
- Your client authenticates with Azure AD to obtain a JWT access token.
- Include the token on every request:Copy
Authorization: Bearer <access_token>
Authorization
The API enforces RelativityOne permissions:
- Workspace permissions
- Data source permissions
If an action isn’t allowed in the RelativityOne UI for a given identity, it is not allowed via the API.
If the caller lacks the required permissions:
- The API returns 403 Forbidden with an authorization error code (for example, COLLECT/UNAUTHORIZED_WORKSPACE).
Scopes
Depending on how your tenant is configured, you may see scopes such as:
- collect.read
- Read collection status, usage, metrics, and data-source capabilities
- collect.manage
- Create, validate, start, stop, retry, resume collections
- Manage webhooks
Error Model
All non-2xx responses use a standard JSON envelope:
1
2
3
4
5
6
7
8
{
"code": "COLLECT/INVALID_CRITERIA",
"message": "Date range end must be after start.",
"details": [
{ "field": "criteria.date_range", "reason": "END_BEFORE_START" }
],
"correlation_id": "a1b2c3d4-e5f6-7890-abcd-1234567890ef"
}
- code (string) - short, machine-readable error code. Common error codes:
- COLLECT/UNAUTHENTICATED – missing or invalid auth token.
- COLLECT/UNAUTHORIZED_WORKSPACE – caller lacks permission for workspace.
- COLLECT/UNAUTHORIZED_SOURCE – caller lacks permission for data source.
- COLLECT/INVALID_REQUEST – malformed JSON or missing required fields.
- COLLECT/INVALID_CRITERIA – search/collection criteria invalid.
- COLLECT/INVALID_STATE_TRANSITION – action not allowed in current job state.
- COLLECT/NOT_FOUND – workspace or collection not found.
- COLLECT/IDEMPOTENCY_CONFLICT – same idempotency key with different payload.
- COLLECT/QUOTA_EXCEEDED – tenant or workspace limit exceeded.
- COLLECT/DEPENDENCY_THROTTLE – upstream service throttling (for example, 429 from M365).
- COLLECT/INTERNAL_ERROR – unexpected server error.
- message (string) - human-readable description. Safe to show in logs or basic UI.
- details (array, optional) - additional field-level information, especially for validation errors.
- correlation_id (string) - unique ID for the request. Logged end-to-end by Relativity and used for support.
Always capture correlation_id in your logs.
Idempotency & Rate Limits
The following section describes the idempotency and rate limits.
Idempotency
To protect against accidental duplicates, create-style operations are idempotent.
- Include a client_request_id (UUID) on collection creation requests.
- For 24 hours:
- The first request creates the collection.
- A subsequent request with the same client_request_id and identical payload returns the original 200 OK and the same collection ID.
- If the payload differs, you receive a 409 Conflict with COLLECT/IDEMPOTENCY_CONFLICT.
Action endpoints (start/stop/resume/target-generation) are designed to be idempotent: calling them again while the job is already in that state will not create duplicate work and will return the current job state.
Rate limits & concurrency
The platform enforces per-tenant:
- Requests per second (QPS)
- Max concurrent collection jobs
These values vary by tenant and environment. Use response headers to inspect limits:
- X-RateLimit-Limit
- X-RateLimit-Remaining
- X-RateLimit-Reset (epoch seconds until reset)
- X-Concurrency-Limit
- X-Concurrency-Remaining
If you exceed a limit you may see 429 Too Many Requests or COLLECT/QUOTA_EXCEEDED.
Data Models
Names here are conceptual schema names; in code they map to DTOs like CreateCollectionAPIModel, CollectionJobModel, etc.
CollectionJobModel
The following code sample illustrates the current state of a collection job.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
"collection_id": "col_01HZX3...",
"collection_artifact_id": 123456,
"workspace_id": 987654,
"data_source": "M365", // e.g. M365, Google, Teams, Slack
"status": "PENDING_VALIDATION", // see values below
"created_at": "2025-11-10T15:20:31Z",
"updated_at": "2025-11-10T15:33:02Z",
"created_by": "spn:abcd-1234...", // service principal or user
"criteria": { /* normalized criteria – see 5.2 */ },
"targets": {
"custodians": [
{ "id": "user_abc", "kind": "M365User" }
],
"groups": [
{ "id": "group_xyz", "kind": "M365Group" }
]
},
"metrics": {
"percent_complete": 42.3,
"items_collected": 154233,
"bytes_collected": 987654321,
"estimated_total_items": 350000,
"estimated_total_bytes": 2500000000,
"retries": 12,
"eta_seconds": 7200
},
"last_run": {
"run_id": "run_01JK...",
"started_at": "2025-11-10T15:25:10Z",
"ended_at": null,
"checkpoint_token": "chk_aaabbb",
"error": null
},
"delivery": {
"type": "DirectToReview", // DirectToReview | Staging | ExternalStorage
"location": "adls://tenant/workspace_987654/ingest"
}
}Status values:
- PENDING_VALIDATION – created, criteria/targets not yet validated.
- READY – validation completed, ready to run.
- RUNNING – active collection run in progress.
- STOPPING – stop requested; run is shutting down gracefully.
- STOPPED – stopped with a checkpoint; can be resumed.
- COMPLETED – finished successfully.
- FAILED – completed with errors.
- CANCELED – canceled by user/system.
Criteria (normalized)
The following code sample illustrates how to describe what to collect (date range, query, etc.):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"source": "M365",
"date_range": {
"from": "2025-09-01T00:00:00Z",
"to": "2025-10-01T00:00:00Z"
},
"query": {
"op": "AND",
"clauses": [
{ "field": "itemClass", "op": "IN", "values": ["Mail", "TeamsMessage"] },
{ "field": "keywords", "op": "CONTAINS", "value": "\"project alpha\"" }
]
}
}
CreateCollectionAPIModel (request)
The following code sample illustrates how to create a new collection job.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"client_request_id": "3f4a0b7e-0f2a-4a67-bb0f-9c7c2e6a12ab",
"workspace_id": "w_123",
"data_source": "M365",
"targets": {
"custodians": [
{ "id": "user_abc", "kind": "M365User" }
]
},
"criteria": {
"date_range": {
"from": "2025-09-01T00:00:00Z",
"to": "2025-10-01T00:00:00Z"
},
"query": {
"op": "AND",
"clauses": [
{ "field": "itemClass", "op": "IN", "values": ["Mail"] }
]
}
},
"delivery": {
"type": "DirectToReview",
"location": "adls://tenant/w_123/ingest"
}
}
StartJobResult
The following code sample illustrates what is returned when a background job, target generation or collection run, is started.
1
2
3
4
5
6
7
{
"job_id": "job_01TG...",
"collection_artifact_id": 123456,
"status": "QUEUED", // QUEUED | RUNNING | COMPLETED | FAILED
"submitted_at": "2025-11-10T15:25:10Z",
"estimated_completion_seconds": 120
}TargetGenerationJobResults
The following code sample illustrates what is returned by the target generation job result endpoint.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
"job_id": "job_01TG...",
"collection_artifact_id": 123456,
"status": "COMPLETED", // or RUNNING, FAILED, etc.
"targets": {
"custodians": [
{ "id": "user_abc", "kind": "M365User" }
],
"groups": [
{
"id": "group_xyz",
"kind": "M365Group",
"expanded_count": 134
}
]
},
"normalized_criteria": {
/* canonical criteria tree – see 5.2 */
},
"estimated_counts": {
"items": 380000,
"bytes": 2700000000
},
"warnings": [
{
"code": "PARTIAL_EXPANSION",
"message": "2 group members could not be resolved."
}
],
"error": null
}Webhook subscription
The following code sample illustrates how to manage webhook subscription via the webhook endpoints.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"webhook_id": "wh_01LM...",
"url": "https://example.com/relativity/events",
"events": [
"COLLECTION.CREATED",
"COLLECTION.VALIDATED",
"RUN.STARTED",
"RUN.PROGRESSED",
"RUN.COMPLETED",
"RUN.FAILED",
"COLLECTION.STOPPED"
],
"hmac_secret_id": "kv://keyvault/secrets/wh-abc",
"active": true,
"created_at": "2025-11-10T15:00:00Z"
}Webhook event payload
HTTP headers
- X-Rel-Signature: sha256=<hex> – HMAC-SHA256 over the raw request body
- X-Rel-Event: RUN.COMPLETED – Event type
- X-Rel-Delivery-Id: dly_01XY... – Delivery identifier
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"event": "RUN.COMPLETED",
"tenant_id": "t_001",
"workspace_id": "w_123",
"collection_id": "col_01HZX3...",
"run_id": "run_01JK...",
"timestamp": "2025-11-10T16:01:02Z",
"metrics": {
"items_collected": 350000,
"bytes_collected": 2500000000,
"retries": 24,
"duration_seconds": 21450
},
"status": "COMPLETED"
}Your webhook listener must:
Verify the HMAC signature using your shared secret.
Handle duplicate deliveries (at-least-once semantics).
Endpoint Reference (CollectAPIController v1)
All paths below are relative to:
/vi/CollectAPIReplace v1 with the appropriate version when it changes.
Create Collection
To create a new collection job in the specified workspace, send a PUT request to the following URL. The job is created in state PENDING_VALIDATION.
Set the path parameters as follows:
- workspaceId / workspaceArtifactId – integer identifier of the Relativity workspace.
workspaceId and workspaceArtifactId both refer to the workspace artifact ID.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"client_request_id": "3f4a0b7e-0f2a-4a67-bb0f-9c7c2e6a12ab",
"workspace_id": "w_123",
"data_source": "M365",
"targets": {
"custodians": [
{ "id": "user_abc", "kind": "M365User" }
]
},
"criteria": {
"date_range": {
"from": "2025-09-01T00:00:00Z",
"to": "2025-10-01T00:00:00Z"
},
"query": {
"op": "AND",
"clauses": [
{ "field": "itemClass", "op": "IN", "values": ["Mail"] }
]
}
},
"delivery": {
"type": "DirectToReview",
"location": "adls://tenant/w_123/ingest"
}
}artifactId is the collection artifact identifier (collectionArtifactId) used in subsequent calls.
Error responses
- 400 Bad Request – Invalid criteria, targets, or request body.
- 401 Unauthorized – Missing/invalid auth token.
- 403 Forbidden – Caller lacks workspace/data source permissions.
- 409 Conflict – Idempotency conflict (same client_request_id with different payload).
- 500 Internal Server Error
All error bodies use the standard error envelope. For more information, see Error Model.
Start Target Generation
Starts an asynchronous target generation job for the specified collection. This typically resolves custodian inputs, expands groups, and normalizes criteria so you can preview/validate impact before running the collection.
/v1/CollectAPI/{workspaceId}/collection/{collectionArtifactId}/start-target-generationSet the path parameters as follows:
- workspaceId / workspaceArtifactId – integer identifier of the Relativity workspace.
- collectionArtifactId – integer identifier of the collection job artifact.
workspaceId and workspaceArtifactId both refer to the workspace artifact ID.
The request body is empty.
1
2
3
4
5
6
7
{
"job_id": "job_01TG...",
"collection_artifact_id": 123456,
"status": "QUEUED",
"submitted_at": "2025-11-10T15:25:10Z",
"estimated_completion_seconds": 120
}Error responses:
- 400 Bad Request – Collection not in a state that allows target generation.
- 401 Unauthorized
- 403 Forbidden
- 404 Not Found – Collection or workspace not found.
- 409 Conflict – A target generation job is already in progress.
- 500 Internal Server Error
Get Target Generation Job Results
Fetches the status and results of a previously started target generation job.
GET /v1/CollectAPI/{workspaceArtifactId}/collection/{collectionArtifactId}/target-generationSet the path parameters as follows:
- workspaceId / workspaceArtifactId – integer identifier of the Relativity workspace.
- collectionArtifactId – integer identifier of the collection job artifact.
workspaceId and workspaceArtifactId both refer to the workspace artifact ID.
The request body is empty.
Successful response
200 OK
Copy1 2 3 4 5 6 7 8 9 10
{
"job_id": "job_01TG...",
"collection_artifact_id": 123456,
"status": "COMPLETED",
"targets": { /* resolved custodians, groups, etc. */ },
"normalized_criteria": { /* canonical criteria */ },
"estimated_counts": { "items": 380000, "bytes": 2700000000 },
"warnings": [],
"error": null
}
Error responses:
- 400 Bad Request – Invalid request or job ID.
- 401 Unauthorized
- 403 Forbidden
- 404 Not Found – Job or collection not found.
- 500 Internal Server Error
Start Collection
To start the collection run for a validated collection. This moves the collection into RUNNING and starts collecting items from the data source according to the criteria and targets, send a PATCH request to the following URL:
PATCH /v1/CollectAPI/{workspaceArtifactId}/collection/{collectionArtifactId}/start-collectionSet the path parameters as follows:
- workspaceId / workspaceArtifactId – integer identifier of the Relativity workspace.
- collectionArtifactId – integer identifier of the collection job artifact.
workspaceId and workspaceArtifactId both refer to the workspace artifact ID.
Preconditions
Collection status must be READY (or equivalent validated state).
The body of the request is empty.
1
2
3
4
5
6
{
"job_id": "run_01JK...",
"collection_artifact_id": 123456,
"status": "RUNNING",
"submitted_at": "2025-11-10T15:25:10Z"
}Error responses:
- 400 Bad Request – Invalid state transition (for example, collection not READY), invalid request.
- 401 Unauthorized
- 403 Forbidden
- 404 Not Found
- 409 Conflict – A run is already in progress for this collection.
- 500 Internal Server Error
- 503 Service Unavailable – Temporary service issue (for example, dependency outage).
Get Collection Status
To return the current status and metadata of a specific collection job, send a GET request to the following URL:
GET /v1/CollectAPI/{workspaceArtifactId}/collection/{collectionArtifactId}Set the path parameters as follows:
- workspaceId / workspaceArtifactId – integer identifier of the Relativity workspace.
- collectionArtifactId – integer identifier of the collection job artifact.
workspaceId and workspaceArtifactId both refer to the workspace artifact ID.
Successful response
- 200 OK – CollectionJobModel.
Copy
1 2 3 4 5 6 7 8 9 10
{
"collection_id": "col_01HZX3...",
"collection_artifact_id": 123456,
"workspace_id": 987654,
"data_source": "M365",
"status": "RUNNING",
"metrics": { "percent_complete": 42.3, "items_collected": 154233, ... },
"last_run": { "run_id": "run_01JK...", "started_at": "2025-11-10T15:25:10Z", ... },
"delivery": { "type": "DirectToReview", "location": "adls://..." }
}
Error responses:
- 400 Bad Request
- 401 Unauthorized
- 403 Forbidden
- 404 Not Found
- 500 Internal Server Error
- 503 Service Unavailable
Stop Collection Job
To stop a collection job, send a PATCH request to the following URL:
PATCH /v1/CollectAPI/{workspaceId}/collection/{collectionArtifactId}/stopThe system will checkpoint progress and transition the collection to STOPPING and then STOPPED. From there it can RESUME later.
Set the path parameters as follows:
- workspaceId / workspaceArtifactId – integer identifier of the Relativity workspace.
- collectionArtifactId – integer identifier of the collection job artifact.
workspaceId and workspaceArtifactId both refer to the workspace artifact ID.
Preconditions
- Collection status must be RUNNING.
The request body is empty.
1
2
3
{
"message": "Stop request accepted. Collection will transition to STOPPED shortly."
}Stopping is asynchronous; poll Get Collection Status to see the final state and checkpoint.
Error responses:
- 400 Bad Request – invalid state transition (for example, collection not RUNNING).
- 401 Unauthorized
- 403 Forbidden
- 404 Not Found
- 409 Conflict – a stop request is already in progress or job is not stoppable
- 500 Internal Server Error
Additional (logical) endpoints from the model
While not all of these are visible on the CollectAPIController excerpt, the API surface includes or may include:
- List collections – filter and paginate collections per workspace
- List artifacts/delivery outputs – where collected data was delivered
- Usage & quotas – aggregate usage metrics per tenant
- Job metrics – throughput and retry telemetry
- Webhook subscriptions – create/list/delete webhooks
Typical shapes (for reference):
List collections
GET /v1/collection?status=RUNNING&data_source=M365&workspace_id=w_123&limit=50&cursor=...1
2
3
4
5
6
7
8
9
10
11
12
{
"collections": [
{
"collection_id": "col_01HZX3...",
"status": "RUNNING",
"workspace_id": "w_123",
"data_source": "M365",
"created_at": "2025-11-10T15:20:31Z"
}
],
"next_cursor": "eyJwYWdlIjoyfQ=="
}For more information, see pagination.
Webhook endpoints
- POST /v1/webhooks – create
- GET /v1/webhooks – list
- DELETE /v1/webhooks/{webhook_id} – delete
1
2
3
4
5
6
7
8
9
10
11
12
{
"url": "https://example.com/relativity/events",
"events": [
"COLLECTION.CREATED",
"COLLECTION.VALIDATED",
"RUN.STARTED",
"RUN.PROGRESSED",
"RUN.COMPLETED",
"RUN.FAILED",
"COLLECTION.STOPPED"
]
}Delivery semantics:
- At-least-once delivery with exponential backoff for ~24 hours
- Non-2xx responses are retried
- Final failure is recorded as an audit event (not delivered as a webhook)
Limits & Constraints (v1)
- Targets per request: up to ~30 logical targets per collection (custodians + groups).
- One active run per collection: Only one RUNNING run permitted for a given collection at a time.
- No raw content exposed via API or webhook payloads (metadata only).
- Sandbox tenants may have lower QPS and concurrency limits.
State machine
The collection life-cycle is enforced by the backend. Valid transitions:
- PENDING_VALIDATION → READY → RUNNING → (COMPLETED | FAILED | STOPPING)
- STOPPING → STOPPED → (CANCELED or RUNNING via Resume)
Attempts to perform an invalid transition return:
- 400 Bad Request with code = "COLLECT/INVALID_STATE_TRANSITION"
Monitoring, Audit & Usage
Every API call emits an audit record that includes:
- Actor (service principal/user)
- Action (for example, START_COLLECTION)
- Workspace and data source
- Outcome (success/failure)
- correlation_id, for more information see, Error Model.
Metrics (per collection and across tenants) available via:
- /metrics endpoint (per collection)
- Platform dashboards
Typical metrics:
- Time spent in each state (p95)
- Job duration, success/failure rate
- Items and bytes collected
- Throughput (items/sec, bytes/sec)
- Retry counts (transient vs permanent)
- Target resolution success/failure
- Upstream throttling (429) and error taxonomy
Security
- Transport: TLS 1.2+ enforced at gateway.
- Authentication: OAuth2 Client Credentials (Azure AD).
- Authorization: RelativityOne workspace and data-source permissions.
- Secrets: Stored in Azure Key Vault; never logged in plaintext.
- Webhooks: HMAC-SHA256 signature via X-Rel-Signature. Customers must verify.
- Privacy: No raw end-user content in API or webhook bodies; metadata only.
Pagination & Filtering
List endpoints follow a simple cursor-based pagination pattern.
Request parameters:
- limit – max number of items to return:
- Default: 50
- Max: 200
- cursor – opaque string returned by previous response; pass it back to get the next page.
Common filters (where supported):
- status – collection status (for example, RUNNING, COMPLETED)
- data_source – M365, Google, etc.
- workspace_id – workspace filter
- created_from, created_to – ISO timestamps
If next_cursor is absent or null, there are no more results.
Always treat cursor as opaque; do not attempt to parse or modify it.
End-to-End Example (cURL)
Below is a typical flow using the conceptual v1 paths. Adapt the base path to /v1/CollectAPI/{workspaceId} where appropriate.
Create a collection
The following code sample illustrates how to create a collection:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
curl -s -X PUT "https://api.relativityone.tld/v1/CollectAPI/987654/collection" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"client_request_id": "3f4a0b7e-0f2a-4a67-bb0f-9c7c2e6a12ab",
"workspace_id": "w_123",
"data_source": "M365",
"targets": {
"custodians": [{ "id": "user_abc", "kind": "M365User" }]
},
"criteria": {
"date_range": {
"from": "2025-09-01T00:00:00Z",
"to": "2025-10-01T00:00:00Z"
}
},
"delivery": {
"type": "DirectToReview",
"location": "adls://tenant/w_123/ingest"
}
}'Start target generation
The following code sample illustrates how to start target generation:
1
2
3
curl -s -X POST \
"https://api.relativityone.tld/v1/CollectAPI/987654/collection/123456/start-target-generation" \
-H "Authorization: Bearer $TOKEN"Poll target generation results
The following code sample illustrates poll target generation results. Use the estimates and warnings to adjust query/targets if needed.
1
2
3
curl -s \
"https://api.relativityone.tld/v1/CollectAPI/987654/collection/123456/target-generation" \
-H "Authorization: Bearer $TOKEN"Start the collection
The following code sample illustrates how to start the collection:
1
2
3
curl -s -X PATCH \
"https://api.relativityone.tld/v1/CollectAPI/987654/collection/123456/start-collection" \
-H "Authorization: Bearer $TOKEN"Poll collection status
The following code sample illustrates poll collection status:
1
2
3
curl -s \
"https://api.relativityone.tld/v1/CollectAPI/987654/collection/123456" \
-H "Authorization: Bearer $TOKEN"Stop the collection (optional)
The following code sample illustrates how to stop the collection:
1
2
3
curl -s -X PATCH \
"https://api.relativityone.tld/v1/CollectAPI/987654/collection/123456/stop" \
-H "Authorization: Bearer $TOKEN"Read artifacts/delivery outputs
The following code sample illustrates read artifacts/delivery outputs. Exact path may differ depending on controller split; conceptually:
1
2
3
curl -s \
"https://api.relativityone.tld/v1/collection/col_01HZX3.../artifacts" \
-H "Authorization: Bearer $TOKEN"