Skip to content

Import a traceability matrix as links (a dry run by default)

POST
/v1/projects/{id}/requirements/import/links
curl --request POST \
--url https://beta-api.plune.ai/v1/projects/example/requirements/import/links \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "markdown": "# Traceability\n\n| Requirement | Test |\n|---|---|\n| REQ-FN-001 | Sign in with an e-mail link |\n| REQ-FN-002, REQ-FN-003 | Export an invoice as PDF |\n", "table": 0, "requirementColumn": "Requirement", "testColumn": "Test", "requirementSeparator": "," }'

A table of a Markdown file with a column of requirement keys and a column of tests (#1608, epic #1594). A requirement is matched by its key (any case); a test by the exact title of a live case of the project or, for an automated case, by its specRef path. A row that matches nothing, or more than one case, is listed as unmatched with the reason: nothing is guessed. A pair already linked is unchanged, so a second import changes nothing. A requirement cell may hold several keys, split by requirementSeparator (default ,). dryRun is true unless the body says false: a dry run writes nothing; dryRun: false adds the new links in ONE transaction and answers the same report with applied: true. Links never override the computed coverage: it still comes from each case’s last result. An applied import is ONE audit entry with the counts. An owner or a member (a reader gets 403); a bearer token only in the project it was minted in. A file over 1 MiB, or a table over 2000 rows, or a report over 2000 rows once the cells are split, is a 413; an unknown table or column is a 400 naming the headers.

id
required
string

An id from GET /v1/projects

Media type application/json
object
markdown
required

The file’s text, at most 1048576 bytes (1 MiB).

string
dryRun

Default true: nothing is written. false adds the new links in one transaction.

boolean
default: true
table
required

The matrix: its index from the discover call.

integer
requirementColumn
required

The header of the column with requirement keys.

string
testColumn
required

The header of the column with test names or source paths (one per line, <br> between them). It is never split by requirementSeparator.

string
requirementSeparator

Splits a requirement cell into several keys (REQ-12, REQ-13); each part is trimmed, an empty part is dropped, a repeated key in one cell counts once, and each key is its own row of the report (same line). Only this text splits a cell: nothing else (;, a new line) is guessed.

string
default: , >= 1 characters <= 3 characters
Example
{
"markdown": "# Traceability\n\n| Requirement | Test |\n|---|---|\n| REQ-FN-001 | Sign in with an e-mail link |\n| REQ-FN-002, REQ-FN-003 | Export an invoice as PDF |\n",
"table": 0,
"requirementColumn": "Requirement",
"testColumn": "Test",
"requirementSeparator": ","
}

The report - the same for a dry run and for an applied import

Media type application/json
object
dryRun
required
boolean
applied
required

true once written; a dry run is false.

boolean
summary
required
object
link
required
integer
unchanged
required
integer
unmatched
required
integer
items
required

One per requirement-test pair of the table, in file order. unmatched rows say why: no requirement with that key, an archived requirement, no case with that exact title or path, or more than one.

Array<object>
object
line
required

1-based line of the row.

integer
action
required
string
Allowed values: link unchanged unmatched
key
required
string
test
required
string
reason
required
string
requirementId
string
caseId
string
Example
{
"dryRun": true,
"applied": false,
"summary": {
"link": 1,
"unchanged": 0,
"unmatched": 1
},
"items": [
{
"line": 5,
"action": "link",
"key": "REQ-FN-001",
"test": "Sign in with an e-mail link",
"reason": "new",
"requirementId": "req_1",
"caseId": "case_1"
},
{
"line": 6,
"action": "unmatched",
"key": "REQ-FN-002",
"test": "Export an invoice as PDF",
"reason": "no case with this exact title or source path",
"requirementId": "req_2"
}
]
}

Invalid JSON or body; an unknown column (the message lists the headers) or table

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

No / invalid token or session

You are in the project as a reader

No such project among yours (or a token of another project)

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

The markdown is over 1 MiB, or the table has more than 2000 rows

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

Rate-limited: the per-route throttle, or the per-minute request limit of the plan an API token counts by (#1442; the body names the plan, #2092). Retry-After carries the seconds until the window rolls over.

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}
Retry-After
integer

Seconds until the window rolls over