Import lifecycle
Upload raw CSV bytes, validate the batch, review validation, commit, then inspect history/skipped rows. Upload alone adds no commercial records. Discover project IDs first.
Upload a raw evidence file
Operation: imports.upload · POST /imports
Upload raw UTF-8 delimited bytes, or UTF-16LE with BOM; never multipart. Maximum 5242880 bytes and 50000 rows. Query kind selects the evidence type. Send text/csv, text/plain or application/vnd.ms-excel and a bounded percent-encoded X-File-Name. The 20-row preview and deterministic alias mapping do not commit evidence or invoke a model. AI usage imports accept only the aggregate template and uniquely matching existing project names, refusing prompts/code/personal identifiers/unsupported columns before storage. Other unknown project names remain unattributed rather than creating projects. Exact scope and current creator action are required. Writes retain the owner/admin check even when a supplemental role grants an action. Foreign/missing references return 404, invalid input 400, closed/conflicting work 409. Required Idempotency-Key safely replays identical normalized requests without repeated rows/audit/mapping charges. Throttling returns 429 with Retry-After. Shared domain schemas retain money/date/unit semantics.
Required key scope: imports:write. Current creator action: integrations.manage. Eligible plans: free, starter, growth, scale; legacy contracts: free, entry, growth. stable contract. These badges do not override current role, evidence window, quotas or target ownership.
-
Engagement/project references belong to the same workspace and each other, with current creator dataset access.
-
Raw files are bounded bytes, never multipart; filenames use valid percent encoding without control characters.
-
Partial AI aggregate imports are unavailable and deterministic mapping never calls a paid model.
-
History distinguishes uncommitted uploads, committed counts, skips and failure.
Parameters (required flags, defaults, units and bounds are the canonical schema):
View schema or synthetic response
[
{
"example": "time_entries",
"in": "query",
"name": "kind",
"required": true,
"schema": {
"enum": [
"rates",
"budgets",
"invoices",
"cloud_cost",
"time_entries",
"work_items",
"code_changes",
"releases",
"calendar_events",
"ai_usage"
],
"type": "string"
}
},
{
"example": "example-imports.upload",
"in": "header",
"name": "idempotency-key",
"required": true,
"schema": {
"pattern": "^[\\x21-\\x7e]{1,200}quot;,
"type": "string"
}
},
{
"example": "example-time.csv",
"in": "header",
"name": "x-file-name",
"required": false,
"schema": {
"maxLength": 1200,
"minLength": 1,
"type": "string"
}
},
{
"example": "text/csv",
"in": "header",
"name": "content-type",
"required": true,
"schema": {
"pattern": "^(text\\/(csv|plain)|application\\/vnd\\.ms-excel)(;.*)?quot;,
"type": "string"
}
}
]
Request body schema:
View schema or synthetic response
{
"content": {
"application/vnd.ms-excel": {
"schema": {
"format": "binary",
"minLength": 1,
"type": "string",
"x-maxBytes": 5242880
}
},
"text/csv": {
"schema": {
"format": "binary",
"minLength": 1,
"type": "string",
"x-maxBytes": 5242880
}
},
"text/plain": {
"schema": {
"format": "binary",
"minLength": 1,
"type": "string",
"x-maxBytes": 5242880
}
}
},
"required": true
}
Success statuses: 200. The JSON response is the saved/read representation. Synthetic examples below show shape, not customer evidence.
Synthetic response:
View schema or synthetic response
{
"batchId": "11111111-1111-4111-8111-111111111111",
"fileName": "example-time.csv",
"headers": [
"Worked on",
"Hours",
"Person alias",
"Project"
],
"kind": "time_entries",
"rowCount": 1,
"sampleRows": [
{
"Hours": "2",
"Person alias": "example-engineer",
"Project": "Example delivery",
"Worked on": "2026-10-01"
}
],
"suggestedMapping": {
"columns": {
"billable": null,
"engagement": null,
"externalId": null,
"hours": "Hours",
"note": null,
"personExternalId": "Person alias",
"project": "Project",
"role": null,
"workedOn": "Worked on",
"workItemExternalKey": null
},
"options": {
"dateFormat": "iso",
"decimalSeparator": ".",
"hoursUnit": "hours"
}
},
"targetFields": [
{
"aliases": [
"workedOn",
"date",
"day",
"work date",
"spent on",
"Worked on"
],
"field": "workedOn",
"label": "Worked on",
"required": true,
"type": "date"
},
{
"aliases": [
"hours",
"hours spent",
"duration",
"duration h",
"time",
"time spent",
"Hours"
],
"field": "hours",
"label": "Hours",
"required": true,
"type": "number"
},
{
"aliases": [
"personExternalId",
"person",
"alias",
"member",
"user",
"initials",
"Person alias"
],
"field": "personExternalId",
"help": "An alias, never a legal name.",
"label": "Person alias",
"required": false,
"type": "string"
},
{
"aliases": [
"role",
"position",
"grade",
"band",
"Role"
],
"field": "role",
"label": "Role",
"required": false,
"type": "string"
},
{
"aliases": [
"billable",
"is billable",
"Billable"
],
"field": "billable",
"label": "Billable",
"required": false,
"type": "boolean"
},
{
"aliases": [
"workItemExternalKey",
"ticket",
"issue",
"issue key",
"key",
"task",
"Work item key"
],
"field": "workItemExternalKey",
"label": "Work item key",
"required": false,
"type": "string"
},
{
"aliases": [
"note",
"description",
"comment",
"details",
"Note"
],
"field": "note",
"label": "Note",
"required": false,
"type": "string"
},
{
"aliases": [
"project",
"project name",
"project_name",
"engagement project",
"Project"
],
"field": "project",
"help": "Matched to an existing project by name. Rows naming an unknown project are imported unattributed rather than creating one.",
"label": "Project",
"required": false,
"type": "string"
},
{
"aliases": [
"engagement",
"engagement name",
"contract",
"Engagement"
],
"field": "engagement",
"label": "Engagement",
"required": false,
"type": "string"
},
{
"aliases": [
"externalId",
"id",
"entry id",
"time entry id",
"external id"
],
"field": "externalId",
"label": "Entry ID",
"required": false,
"type": "string"
}
]
}
Use IDs and versions from your own preceding responses. Replace the synthetic UUIDs, dates and names in these independent examples. Set SCOPEWORTH_API_BASE and SCOPEWORTH_API_KEY only on your server.
Save these synthetic bytes as example-time.csv:
Worked on,Hours,Person alias,Project
2026-10-01,2,example-engineer,Example delivery
cURL
curl --request POST "$SCOPEWORTH_API_BASE/organizations/example-org/workspaces/example-workspace/imports?kind=time_entries" \
--header 'x-file-name: example-time.csv' \
--header 'content-type: text/csv' \
--header "Authorization: Bearer $SCOPEWORTH_API_KEY" \
--header 'Content-Type: text/csv' \
--header 'Idempotency-Key: example-operation-attempt-1' \
--data-binary @example-time.csvJavaScript fetch
// Run on your server. API_BASE ends in /api/v1 (combined host) or /v1 (verified cell).
import { readFile } from "node:fs/promises";
const response = await fetch(process.env.SCOPEWORTH_API_BASE + "/organizations/example-org/workspaces/example-workspace/imports?kind=time_entries", {
method: "POST",
headers: {
"x-file-name": "example-time.csv",
"content-type": "text/csv",
"Authorization": `Bearer ${process.env.SCOPEWORTH_API_KEY}`,
"Content-Type": "text/csv",
"Idempotency-Key": "example-operation-attempt-1"
},
body: await readFile("example-time.csv"),
});
if (!response.ok) throw new Error(`ScopeWorth refused request: ${response.status}`);
const result = await response.json();Python requests
import os, requests, pathlib
headers = {"x-file-name":"example-time.csv","content-type":"text/csv","Authorization":"Bearer " + os.environ["SCOPEWORTH_API_KEY"],"Content-Type":"text/csv","Idempotency-Key":"example-operation-attempt-1"}
response = requests.request("POST", os.environ["SCOPEWORTH_API_BASE"] + "/organizations/example-org/workspaces/example-workspace/imports?kind=time_entries", headers=headers, data=pathlib.Path("example-time.csv").read_bytes(), timeout=30)
response.raise_for_status()
result = response.json()For refusals, follow error recovery. A scope or plan badge is eligibility, not proof of authorization or available evidence. Read current directory IDs and versions before correcting a request. Keep an idempotency key for one unchanged mutation attempt; never blindly retry uncertain external work.
Use the generated Content-Type and x-file-name headers. This is raw bytes, not multipart or JSON CSV. Save the generated synthetic CSV as example-time.csv. A filename is metadata, not a local path. Supported encodings and rows follow the parser/validation output.
Confirm and validate a column mapping
Operation: imports.validate · POST /imports/:batchId/validate
Save the chosen field-to-header mapping and validate uploaded rows, with date format, decimal separator, hours unit and optional currency. validRows, invalidRows, alreadyImported and repeatedInFile are distinct outcomes. No domain rows are committed. Deterministic suggestions do not call AI or charge tokens. Exact scope and current creator action are required. Writes retain the owner/admin check even when a supplemental role grants an action. Foreign/missing references return 404, invalid input 400, closed/conflicting work 409. Required Idempotency-Key safely replays identical normalized requests without repeated rows/audit/mapping charges. Throttling returns 429 with Retry-After. Shared domain schemas retain money/date/unit semantics.
Required key scope: imports:write. Current creator action: integrations.manage. Eligible plans: free, starter, growth, scale; legacy contracts: free, entry, growth. stable contract. These badges do not override current role, evidence window, quotas or target ownership.
-
Engagement/project references belong to the same workspace and each other, with current creator dataset access.
-
Raw files are bounded bytes, never multipart; filenames use valid percent encoding without control characters.
-
Partial AI aggregate imports are unavailable and deterministic mapping never calls a paid model.
-
History distinguishes uncommitted uploads, committed counts, skips and failure.
Parameters (required flags, defaults, units and bounds are the canonical schema):
View schema or synthetic response
[
{
"example": "11111111-1111-4111-8111-111111111111",
"in": "path",
"name": "batchId",
"required": true,
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
}
},
{
"example": "example-imports.validate",
"in": "header",
"name": "idempotency-key",
"required": true,
"schema": {
"pattern": "^[\\x21-\\x7e]{1,200}quot;,
"type": "string"
}
}
]
Request body schema:
View schema or synthetic response
{
"content": {
"application/json": {
"examples": {
"synthetic1": {
"value": {
"columns": {
"billable": null,
"engagement": null,
"externalId": null,
"hours": "Hours",
"note": null,
"personExternalId": "Person alias",
"project": "Project",
"role": null,
"workedOn": "Worked on",
"workItemExternalKey": null
},
"options": {
"dateFormat": "iso",
"decimalSeparator": ".",
"hoursUnit": "hours"
}
}
}
},
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"columns": {
"additionalProperties": {
"type": [
"string",
"null"
]
},
"propertyNames": {
"type": "string"
},
"type": "object"
},
"options": {
"default": {
"dateFormat": "iso",
"decimalSeparator": ".",
"hoursUnit": "hours"
},
"properties": {
"currency": {
"pattern": "^[A-Z]{3}quot;,
"type": "string"
},
"dateFormat": {
"default": "iso",
"enum": [
"iso",
"dmy",
"mdy"
],
"type": "string"
},
"decimalSeparator": {
"default": ".",
"enum": [
".",
","
],
"type": "string"
},
"hoursUnit": {
"default": "hours",
"enum": [
"hours",
"minutes"
],
"type": "string"
}
},
"type": "object"
}
},
"required": [
"columns"
],
"type": "object"
}
}
},
"required": true
}
Success statuses: 200. The JSON response is the saved/read representation. Synthetic examples below show shape, not customer evidence.
Synthetic response:
View schema or synthetic response
{
"alreadyImported": 0,
"batchId": "11111111-1111-4111-8111-111111111111",
"duplicates": 0,
"errors": [],
"errorsTruncated": false,
"invalidRows": 0,
"kind": "time_entries",
"repeatedInFile": 0,
"sample": [
{
"hours": 2,
"personExternalId": "example-engineer",
"project": "Example delivery",
"workedOn": "2026-10-01"
}
],
"validRows": 1
}
Use IDs and versions from your own preceding responses. Replace the synthetic UUIDs, dates and names in these independent examples. Set SCOPEWORTH_API_BASE and SCOPEWORTH_API_KEY only on your server.
cURL
curl --request POST "$SCOPEWORTH_API_BASE/organizations/example-org/workspaces/example-workspace/imports/11111111-1111-4111-8111-111111111111/validate" \
--header "Authorization: Bearer $SCOPEWORTH_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: example-operation-attempt-1' \
--data-raw '{"columns":{"workedOn":"Worked on","hours":"Hours","personExternalId":"Person alias","role":null,"billable":null,"workItemExternalKey":null,"note":null,"project":"Project","engagement":null,"externalId":null},"options":{"dateFormat":"iso","decimalSeparator":".","hoursUnit":"hours"}}'JavaScript fetch
// Run on your server. API_BASE ends in /api/v1 (combined host) or /v1 (verified cell).
const response = await fetch(process.env.SCOPEWORTH_API_BASE + "/organizations/example-org/workspaces/example-workspace/imports/11111111-1111-4111-8111-111111111111/validate", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SCOPEWORTH_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "example-operation-attempt-1"
},
body: JSON.stringify({
"columns": {
"workedOn": "Worked on",
"hours": "Hours",
"personExternalId": "Person alias",
"role": null,
"billable": null,
"workItemExternalKey": null,
"note": null,
"project": "Project",
"engagement": null,
"externalId": null
},
"options": {
"dateFormat": "iso",
"decimalSeparator": ".",
"hoursUnit": "hours"
}
}),
});
if (!response.ok) throw new Error(`ScopeWorth refused request: ${response.status}`);
const result = await response.json();Python requests
import os, requests
headers = {"Authorization":"Bearer " + os.environ["SCOPEWORTH_API_KEY"],"Content-Type":"application/json","Idempotency-Key":"example-operation-attempt-1"}
response = requests.request("POST", os.environ["SCOPEWORTH_API_BASE"] + "/organizations/example-org/workspaces/example-workspace/imports/11111111-1111-4111-8111-111111111111/validate", headers=headers, json=__import__("json").loads("{\"columns\":{\"workedOn\":\"Worked on\",\"hours\":\"Hours\",\"personExternalId\":\"Person alias\",\"role\":null,\"billable\":null,\"workItemExternalKey\":null,\"note\":null,\"project\":\"Project\",\"engagement\":null,\"externalId\":null},\"options\":{\"dateFormat\":\"iso\",\"decimalSeparator\":\".\",\"hoursUnit\":\"hours\"}}"), timeout=30)
response.raise_for_status()
result = response.json()For refusals, follow error recovery. A scope or plan badge is eligibility, not proof of authorization or available evidence. Read current directory IDs and versions before correcting a request. Keep an idempotency key for one unchanged mutation attempt; never blindly retry uncertain external work.
Use batchId from upload. Inspect validation errors, preview and row counts. Correct invalid data and upload a new batch rather than committing blindly. Monetary integer fields use minor units in the selected currency; hours follow their numeric precision.
Commit a validated import
Operation: imports.commit · POST /imports/:batchId/commit
Atomically commit stored workspace-bound rows/mapping. Missing mapping or a closed batch returns 409. Invalid rows with skipInvalid false return 400 without evidence writes; true commits eligible rows and records bounded skips. AI aggregate imports require every row valid and refuse partial commits. Reimports update natural identities. Rates/budgets require an unambiguous engagement and explicit currency. Execution failure rolls back rows and records truthful failed history/audit separately. Exact scope and current creator action are required. Writes retain the owner/admin check even when a supplemental role grants an action. Foreign/missing references return 404, invalid input 400, closed/conflicting work 409. Required Idempotency-Key safely replays identical normalized requests without repeated rows/audit/mapping charges. Throttling returns 429 with Retry-After. Shared domain schemas retain money/date/unit semantics.
Required key scope: imports:write. Current creator action: integrations.manage. Eligible plans: free, starter, growth, scale; legacy contracts: free, entry, growth. stable contract. These badges do not override current role, evidence window, quotas or target ownership.
-
Engagement/project references belong to the same workspace and each other, with current creator dataset access.
-
Raw files are bounded bytes, never multipart; filenames use valid percent encoding without control characters.
-
Partial AI aggregate imports are unavailable and deterministic mapping never calls a paid model.
-
History distinguishes uncommitted uploads, committed counts, skips and failure.
Parameters (required flags, defaults, units and bounds are the canonical schema):
View schema or synthetic response
[
{
"example": "11111111-1111-4111-8111-111111111111",
"in": "path",
"name": "batchId",
"required": true,
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
}
},
{
"example": "example-imports.commit",
"in": "header",
"name": "idempotency-key",
"required": true,
"schema": {
"pattern": "^[\\x21-\\x7e]{1,200}quot;,
"type": "string"
}
}
]
Request body schema:
View schema or synthetic response
{
"content": {
"application/json": {
"examples": {
"synthetic1": {
"value": {
"skipInvalid": false
}
}
},
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"skipInvalid": {
"default": false,
"type": "boolean"
}
},
"type": "object"
}
}
},
"required": true
}
Success statuses: 200. The JSON response is the saved/read representation. Synthetic examples below show shape, not customer evidence.
Synthetic response:
View schema or synthetic response
{
"batchId": "11111111-1111-4111-8111-111111111111",
"inserted": 1,
"kind": "time_entries",
"skipped": 0,
"updated": 0
}
Use IDs and versions from your own preceding responses. Replace the synthetic UUIDs, dates and names in these independent examples. Set SCOPEWORTH_API_BASE and SCOPEWORTH_API_KEY only on your server.
cURL
curl --request POST "$SCOPEWORTH_API_BASE/organizations/example-org/workspaces/example-workspace/imports/11111111-1111-4111-8111-111111111111/commit" \
--header "Authorization: Bearer $SCOPEWORTH_API_KEY" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: example-operation-attempt-1' \
--data-raw '{"skipInvalid":false}'JavaScript fetch
// Run on your server. API_BASE ends in /api/v1 (combined host) or /v1 (verified cell).
const response = await fetch(process.env.SCOPEWORTH_API_BASE + "/organizations/example-org/workspaces/example-workspace/imports/11111111-1111-4111-8111-111111111111/commit", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SCOPEWORTH_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "example-operation-attempt-1"
},
body: JSON.stringify({
"skipInvalid": false
}),
});
if (!response.ok) throw new Error(`ScopeWorth refused request: ${response.status}`);
const result = await response.json();Python requests
import os, requests
headers = {"Authorization":"Bearer " + os.environ["SCOPEWORTH_API_KEY"],"Content-Type":"application/json","Idempotency-Key":"example-operation-attempt-1"}
response = requests.request("POST", os.environ["SCOPEWORTH_API_BASE"] + "/organizations/example-org/workspaces/example-workspace/imports/11111111-1111-4111-8111-111111111111/commit", headers=headers, json=__import__("json").loads("{\"skipInvalid\":false}"), timeout=30)
response.raise_for_status()
result = response.json()For refusals, follow error recovery. A scope or plan badge is eligibility, not proof of authorization or available evidence. Read current directory IDs and versions before correcting a request. Keep an idempotency key for one unchanged mutation attempt; never blindly retry uncertain external work.
Choose allow-skips explicitly. Keep the commit attempt's key for unchanged retries. The result separates added, updated and skipped records; replay must not duplicate additions.
List import batches
Operation: imports.list · GET /imports
Inspect the latest 50 batches, newest first, including parsed/previewed uploads, which are not committed evidence. No pagination. Exact scope and current creator action are required. Writes retain the owner/admin check even when a supplemental role grants an action. Foreign/missing references return 404, invalid input 400, closed/conflicting work 409. Required Idempotency-Key safely replays identical normalized requests without repeated rows/audit/mapping charges. Throttling returns 429 with Retry-After. Shared domain schemas retain money/date/unit semantics.
Required key scope: imports:read. Current creator action: integrations.manage. Eligible plans: free, starter, growth, scale; legacy contracts: free, entry, growth. stable contract. These badges do not override current role, evidence window, quotas or target ownership.
-
Engagement/project references belong to the same workspace and each other, with current creator dataset access.
-
Raw files are bounded bytes, never multipart; filenames use valid percent encoding without control characters.
-
Partial AI aggregate imports are unavailable and deterministic mapping never calls a paid model.
-
History distinguishes uncommitted uploads, committed counts, skips and failure.
Success statuses: 200. The JSON response is the saved/read representation. Synthetic examples below show shape, not customer evidence.
Synthetic response:
View schema or synthetic response
{
"batches": []
}
Use IDs and versions from your own preceding responses. Replace the synthetic UUIDs, dates and names in these independent examples. Set SCOPEWORTH_API_BASE and SCOPEWORTH_API_KEY only on your server.
cURL
curl --request GET "$SCOPEWORTH_API_BASE/organizations/example-org/workspaces/example-workspace/imports" \
--header "Authorization: Bearer $SCOPEWORTH_API_KEY"JavaScript fetch
// Run on your server. API_BASE ends in /api/v1 (combined host) or /v1 (verified cell).
const response = await fetch(process.env.SCOPEWORTH_API_BASE + "/organizations/example-org/workspaces/example-workspace/imports", {
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.SCOPEWORTH_API_KEY}`
},
});
if (!response.ok) throw new Error(`ScopeWorth refused request: ${response.status}`);
const result = await response.json();Python requests
import os, requests
headers = {"Authorization":"Bearer " + os.environ["SCOPEWORTH_API_KEY"]}
response = requests.request("GET", os.environ["SCOPEWORTH_API_BASE"] + "/organizations/example-org/workspaces/example-workspace/imports", headers=headers, timeout=30)
response.raise_for_status()
result = response.json()For refusals, follow error recovery. A scope or plan badge is eligibility, not proof of authorization or available evidence. Read current directory IDs and versions before correcting a request. Keep an idempotency key for one unchanged mutation attempt; never blindly retry uncertain external work.
Read committed and failed history
Operation: imports.history · GET /imports/history
Read the latest 100 committed/failed batches, optionally by kind. Counts cover the complete filtered history; uncommittedCount covers uploads excluded from history. Failed batches wrote no partial evidence. No pagination/export. Exact scope and current creator action are required. Writes retain the owner/admin check even when a supplemental role grants an action. Foreign/missing references return 404, invalid input 400, closed/conflicting work 409. Required Idempotency-Key safely replays identical normalized requests without repeated rows/audit/mapping charges. Throttling returns 429 with Retry-After. Shared domain schemas retain money/date/unit semantics.
Required key scope: imports:read. Current creator action: integrations.manage. Eligible plans: free, starter, growth, scale; legacy contracts: free, entry, growth. stable contract. These badges do not override current role, evidence window, quotas or target ownership.
-
Engagement/project references belong to the same workspace and each other, with current creator dataset access.
-
Raw files are bounded bytes, never multipart; filenames use valid percent encoding without control characters.
-
Partial AI aggregate imports are unavailable and deterministic mapping never calls a paid model.
-
History distinguishes uncommitted uploads, committed counts, skips and failure.
Parameters (required flags, defaults, units and bounds are the canonical schema):
View schema or synthetic response
[
{
"in": "query",
"name": "kind",
"required": false,
"schema": {
"enum": [
"rates",
"budgets",
"invoices",
"cloud_cost",
"time_entries",
"work_items",
"code_changes",
"releases",
"calendar_events",
"ai_usage"
],
"type": "string"
}
}
]
Success statuses: 200. The JSON response is the saved/read representation. Synthetic examples below show shape, not customer evidence.
Synthetic response:
View schema or synthetic response
{
"batches": [],
"canImport": true,
"kindCounts": [],
"total": 0,
"totals": {
"added": 0,
"failed": 0,
"skipped": 0,
"updated": 0
},
"uncommittedCount": 0
}
Use IDs and versions from your own preceding responses. Replace the synthetic UUIDs, dates and names in these independent examples. Set SCOPEWORTH_API_BASE and SCOPEWORTH_API_KEY only on your server.
cURL
curl --request GET "$SCOPEWORTH_API_BASE/organizations/example-org/workspaces/example-workspace/imports/history" \
--header "Authorization: Bearer $SCOPEWORTH_API_KEY"JavaScript fetch
// Run on your server. API_BASE ends in /api/v1 (combined host) or /v1 (verified cell).
const response = await fetch(process.env.SCOPEWORTH_API_BASE + "/organizations/example-org/workspaces/example-workspace/imports/history", {
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.SCOPEWORTH_API_KEY}`
},
});
if (!response.ok) throw new Error(`ScopeWorth refused request: ${response.status}`);
const result = await response.json();Python requests
import os, requests
headers = {"Authorization":"Bearer " + os.environ["SCOPEWORTH_API_KEY"]}
response = requests.request("GET", os.environ["SCOPEWORTH_API_BASE"] + "/organizations/example-org/workspaces/example-workspace/imports/history", headers=headers, timeout=30)
response.raise_for_status()
result = response.json()For refusals, follow error recovery. A scope or plan badge is eligibility, not proof of authorization or available evidence. Read current directory IDs and versions before correcting a request. Keep an idempotency key for one unchanged mutation attempt; never blindly retry uncertain external work.
Inspect skipped-row reasons
Operation: imports.skipped · GET /imports/:batchId/skipped
Read bounded operator-safe reasons for one stored workspace batch. No skips, absent historical reasons and truncated reasons stay distinct. Foreign/missing IDs return 404. Exact scope and current creator action are required. Writes retain the owner/admin check even when a supplemental role grants an action. Foreign/missing references return 404, invalid input 400, closed/conflicting work 409. Required Idempotency-Key safely replays identical normalized requests without repeated rows/audit/mapping charges. Throttling returns 429 with Retry-After. Shared domain schemas retain money/date/unit semantics.
Required key scope: imports:read. Current creator action: integrations.manage. Eligible plans: free, starter, growth, scale; legacy contracts: free, entry, growth. stable contract. These badges do not override current role, evidence window, quotas or target ownership.
-
Engagement/project references belong to the same workspace and each other, with current creator dataset access.
-
Raw files are bounded bytes, never multipart; filenames use valid percent encoding without control characters.
-
Partial AI aggregate imports are unavailable and deterministic mapping never calls a paid model.
-
History distinguishes uncommitted uploads, committed counts, skips and failure.
Parameters (required flags, defaults, units and bounds are the canonical schema):
View schema or synthetic response
[
{
"example": "11111111-1111-4111-8111-111111111111",
"in": "path",
"name": "batchId",
"required": true,
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)quot;,
"type": "string"
}
}
]
Success statuses: 200. The JSON response is the saved/read representation. Synthetic examples below show shape, not customer evidence.
Synthetic response:
View schema or synthetic response
{
"batchId": "11111111-1111-4111-8111-111111111111",
"recorded": true,
"rows": [],
"truncated": false
}
Use IDs and versions from your own preceding responses. Replace the synthetic UUIDs, dates and names in these independent examples. Set SCOPEWORTH_API_BASE and SCOPEWORTH_API_KEY only on your server.
cURL
curl --request GET "$SCOPEWORTH_API_BASE/organizations/example-org/workspaces/example-workspace/imports/11111111-1111-4111-8111-111111111111/skipped" \
--header "Authorization: Bearer $SCOPEWORTH_API_KEY"JavaScript fetch
// Run on your server. API_BASE ends in /api/v1 (combined host) or /v1 (verified cell).
const response = await fetch(process.env.SCOPEWORTH_API_BASE + "/organizations/example-org/workspaces/example-workspace/imports/11111111-1111-4111-8111-111111111111/skipped", {
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.SCOPEWORTH_API_KEY}`
},
});
if (!response.ok) throw new Error(`ScopeWorth refused request: ${response.status}`);
const result = await response.json();Python requests
import os, requests
headers = {"Authorization":"Bearer " + os.environ["SCOPEWORTH_API_KEY"]}
response = requests.request("GET", os.environ["SCOPEWORTH_API_BASE"] + "/organizations/example-org/workspaces/example-workspace/imports/11111111-1111-4111-8111-111111111111/skipped", headers=headers, timeout=30)
response.raise_for_status()
result = response.json()For refusals, follow error recovery. A scope or plan badge is eligibility, not proof of authorization or available evidence. Read current directory IDs and versions before correcting a request. Keep an idempotency key for one unchanged mutation attempt; never blindly retry uncertain external work.
History and skipped rows are bounded. Inspect truncation/counts rather than assuming every rejected row appears in the preview. Audit attribution identifies the API key. Commit success establishes saved records, not complete provider coverage. See technical limits.