XMLRPC Method Reference - sebiboga/testlink-upgraded GitHub Wiki
Full reference for all 89 registered tl.* XML-RPC methods (87 distinct
behaviors - tl.ping/tl.sayHello and tl.reportTCResult/
tl.setTestCaseExecutionResult are aliases). Source of truth:
lib/api/xmlrpc/v1/xmlrpc.class.php.
For the request/response XML shape, authentication (devKey), and worked
tl.createTestSuite/tl.createTestCase examples, see
API-Documentation. This page goes one level deeper:
every method's parameters (required vs optional), what it returns, and
known quirks - written to support writing test cases against each one.
How this page was built: the six categories marked "dogfooded" below were actually called against a running instance with real devKeys, real data, and the responses inspected - that's how issues #451-#456 were found and fixed. The remaining categories are documented from reading the source (params, docblocks, control flow) but were not called live. Where the code reading turned up something that looks like a bug, it's called out explicitly as "not live-verified" - treat those as leads for your own testing, not confirmed defects.
Legend: required params have no brackets; [opt] marks optional
params, with default/behavior noted when relevant.
| Method | Params | Returns | Notes |
|---|---|---|---|
checkDevKey |
devKey |
true / error |
No other params. |
about |
(none - no auth required) | string, API version info | Only method besides the greeting ones that skips auth entirely. |
testLinkVersion |
(zero params) | version string, e.g. "2.0.0"
|
Was fatal with a spec-compliant empty <params> block - fixed #451. |
ping / sayHello
|
(zero params) | "Hello!" |
Aliases of the same handler. Was fatal with empty <params> - fixed #451. |
repeat |
str [opt]
|
"You said: {str}" |
Missing str just yields "You said: ", no crash. |
setTestMode |
testmode (bool) |
true / error |
Param name is lowercase testmode, easy to typo. Used to silently swallow its own error (return false instead of the error struct) - fixed #452. |
| Method | Params | Returns | Notes |
|---|---|---|---|
doesUserExist |
devKey, user (login) |
true / error 10000 |
|
createUser |
devKey, login, firstname, lastname, email, password [opt]
|
new user id / error | Restricted to site admin. Duplicate login -> error 14003. |
setUserRoleOnProject |
devKey, userid, testprojectid, rolename |
true / error |
Restricted to system-wide role admin. Unknown role -> error 15002; used to show the raw string "LOCALIZE: API_ROLE_NAME_DOESNOT_EXIST" instead of a real message - fixed #453. |
getUserByLogin |
devKey, user (login) | full user struct, userApiKey blanked |
Only a site admin or the user looking up themself may call this for a given login. Others used to get a misleading "user not found" instead of a permission error - fixed #454. |
getUserByID |
devKey, userid | full user struct | Same admin-or-self restriction. Used to fatal (undefined constant) for the non-admin/other-user case - fixed #455. |
| Method | Params | Returns | Notes |
|---|---|---|---|
getProjects |
devKey | array of all accessible projects | |
getTestProjectByName |
devKey, testprojectname | single project struct | |
createTestProject |
devKey, testprojectname, testcaseprefix, notes [opt], options [opt map: requirementsEnabled/testPriorityEnabled/automationEnabled/inventoryEnabled], active [opt], public [opt], itsname [opt], itsEnabled [opt]
|
{status,id,message} / error 7002 if name exists |
Requires mgt_modify_product. |
deleteTestProject |
devKey, prefix |
{status:true} / error 7013 |
Requires mgt_modify_product. |
getProjectKeywords |
devKey, testprojectid | {keywordid: keywordname} |
|
getProjectPlatforms |
devKey, testprojectid | {platformname: platform struct} |
Correctly nulls the enable_on_design/execution filters - see #456 for why that matters. |
getProjectTestPlans |
devKey, testprojectid | array of test plans | Empty/null if the project has none. |
createPlatform |
devKey, testprojectname, platformname, notes [opt], platformOnDesign [opt bool, default false], platformOnExecution [opt bool, default false]
|
{status,id} / error 12000 if dup name |
Requires platform_management. Duplicate-name check used to be blind to platforms created with the (default) disabled design/execution flags - fixed #456. |
| Method | Params | Returns | Notes |
|---|---|---|---|
createTestCase |
devKey, testcasename, testsuiteid, testprojectid, authorlogin, summary, steps (array) + preconditions/importance/execution/order/internalid/checkduplicatedname/actiononduplicatedname/status/estimatedexecduration [all opt]
|
result with additionalInfo.external_id
|
Dogfooded. Duplicate external_id struct member bug - fixed #450 (see API-Documentation). |
getTestCaseIDByName |
devKey, testcasename, testsuitename/testprojectname/testcasepathname [opt]
|
array of matches / error | Case-sensitive. |
reportTCResult (alias setTestCaseExecutionResult) |
devKey, (testcaseid OR testcaseexternalid), testplanid, status, + many optionals (buildid/buildname, notes, execduration, guess, bugid, platformid/platformname, customfields, overwrite, user, timestamp) | {status,id,message} |
guess defaults true (server infers missing optional context). |
getTestCasesForTestPlan |
devKey, testplanid + long optional filter list (testcaseid, buildid, keywordid/keywords, executed, assignedto, executestatus, executiontype, getstepinfo, details, customfields, platformid) | map of test cases |
details default is 'full'. |
getTestCasesForTestSuite |
devKey, testsuiteid, deep [opt default true], details [opt default simple], getkeywords [opt default false]
|
array of test cases | Recurses into child suites when deep is true. |
getTestCase |
devKey, (testcaseid OR testcaseexternalid), version [opt, default latest]
|
test case spec | error NO_TESTCASE_FOUND if missing. |
updateTestCase |
devKey, testcaseexternalid + many optionals (version, testcasename, summary, preconditions, steps, importance, executiontype, status, estimatedexecduration, user) |
{status_ok,msg,operation} / error |
Blocks a rename to a duplicate name before applying other fields. If the version has already been executed, additionally requires testproject_edit_executed_testcases. |
createTestCaseSteps |
devKey, (testcaseexternalid OR testcaseid), version [opt, default last active], action (create/update/push - push not implemented), steps (array of {step_number,actions,expected_results,execution_type}) |
result info | Requires mgt_modify_tc. |
deleteTestCaseSteps |
devKey, testcaseexternalid, version [opt], steps (array of step_number ints) |
result info | Requires mgt_modify_tc. |
setTestCaseExecutionType |
devKey, testcaseexternalid, version, testprojectid, executiontype |
[args,debug] / error |
FIXED (#458): its "missing required parameter" message used to name customfields instead of executiontype; now live-verified correct (Suite 458 6/6 PASS). |
setTestCaseTestSuite |
devKey, testcaseexternalid, testsuiteid | success struct / error | Raw SQL move of the test case to a new parent; blocked if the target suite is in a different project. Not live-verified: builds its message prefix from $ret['operation'], but $ret was populated as an indexed array ($ret[0]['operation']) so the real value is unreachable and the prefix silently becomes "() - ". |
getTestCaseAttachments |
devKey, (testcaseid OR testcaseexternalid), version [opt, default latest]
|
map of attachment id -> {id,name,file_type,title,date_added,content(base64)}
|
|
getFullPath |
devKey, nodeID (int OR array of ints) | map of nodeID -> path | Nodes that can't be found return null for that key rather than erroring (by design). |
getTestCaseBugs |
devKey, tplanid, (testcaseid OR testcaseexternalid), platformid/platformname [opt], buildid/buildname [opt], executionid [opt, restricts to one execution]
|
{bugs:[...]} or {id:-1} if never executed |
|
getTestCaseAssignedTester |
devKey, tplanid, testcaseexternalid, (buildid OR buildname), platformid/platformname [mandatory if that link has platforms]
|
{user_id,login,first,last} |
|
assignTestCaseExecutionTask |
devKey, testplanid, testcaseexternalid, (buildid OR buildname), platformid/platformname [mandatory if plan has platforms], user (tester login) |
result | Wraps the private manageTestCaseExecutionTask() with action='assignOne'. |
unassignTestCaseExecutionTask |
same as above, action defaults to unassignOne; pass action='unassignAll' to skip user
|
result | Same private helper. |
getTestCaseKeywords |
devKey, (testcaseid OR testcaseexternalid) - int OR array, version [opt, int or parallel array]
|
map of accessKey -> keyword map | Supports batch lookup across multiple test cases in one call. |
getTestCaseRequirements |
devKey, testcaseversionid | array of requirements | Requires mgt_view_req. |
addTestCaseKeywords |
devKey, keywords (map of testcaseexternalid -> [keyword names]) |
result | Adds to the latest version only. Batch across multiple test cases in one call, all-or-nothing on auth failure. |
removeTestCaseKeywords |
devKey, keywords (same map shape) | result | Same semantics, removes instead. |
getTestCaseCustomFieldDesignValue |
devKey, testcaseexternalid, version, testprojectid, customfieldname, details [opt: value(default)/full/simple]
|
value or struct | |
updateTestCaseCustomFieldDesignValue |
devKey, testcaseexternalid, version, testprojectid, customfields [opt map name->value]
|
null on success / error array |
|
getTestCaseCustomFieldExecutionValue |
devKey, executionid, version, customfieldname | value |
version must match the execution's tcversion_number or you get NO_MATCH. |
getTestCaseCustomFieldTestPlanDesignValue |
devKey, customfieldname, testcaseid (read as nodeid internally - naming in code is inconsistent with the docblock), testplanid, linkid | value |
| Method | Params | Returns | Notes |
|---|---|---|---|
createTestSuite |
devKey, testprojectid, testsuitename, details, parentid [opt, top-level if absent], order [opt], checkduplicatedname [opt default true], actiononduplicatedname [opt]
|
result |
Dogfooded (issue #448, fixed earlier this session). Private containers require global admin or mgt_modify_tc. |
updateTestSuite |
devKey, (testsuiteid OR prefix), testsuitename/details/parentid/order [opt]
|
result | Literally calls createTestSuite() internally with action='update' - shares its code path/bugs. |
getTestSuite |
devKey, testsuitename, prefix | array of matches | Not live-verified, two issues spotted reading the code: (1) the rights-check context is built from an undefined $dummy variable instead of the actually-loaded $tproj, so the real project id never reaches the permission check; (2) the name-matching loop is off-by-one ($ydx <= $l2d where $l2d = count($items)), reading one index past the end of the array. |
getTestSuiteByID |
devKey, testsuiteid, details [opt default simple]
|
suite struct | |
getTestSuitesForTestSuite |
devKey, testsuiteid | direct children only | Not recursive. |
getFirstLevelTestSuitesForTestProject |
devKey, testprojectid | top-level suites | Error TPROJECT_IS_EMPTY if the project has none. |
getTestSuiteAttachments |
devKey, testsuiteid | attachment map | Same shape as getTestCaseAttachments. |
getTestSuiteCustomFieldDesignValue |
devKey, customfieldname, testprojectid, testsuiteid | value | |
updateTestSuiteCustomFieldDesignValue |
devKey, testprojectid, testsuiteid, customfields (map) | array of {status,msg} per field |
FIXED in #460, live-verified: the return used to sit inside the foreach over custom fields (only the first field processed/reported). Now returns after the loop, matching updateBuildCustomFieldsValues. See Bugfix-Issue-460. |
| Method | Params | Returns | Notes |
|---|---|---|---|
createTestPlan |
devKey, testplanname, (testprojectname OR prefix), notes/active/public [opt]
|
{status,id,message} / error if name exists |
Requires mgt_testplan_create unless global admin. |
deleteTestPlan |
devKey, testplanid |
{status,id,message} / error |
Requires exec_delete right (CFG_DELETE_EXEC_DISABLED if missing - shared with deleteExecution). |
getTestPlanByName |
devKey, testprojectname, testplanname | full plan struct / error | |
getTestPlanPlatforms |
devKey, testplanid | array of platforms / error TESTPLAN_HAS_NO_PLATFORMS
|
Not live-verified: references an undefined $messagePrefix (function actually defines $msg_prefix) - drops the error prefix, cosmetic only. |
getTotalsForTestPlan |
devKey, testplanid | map of platform -> {type,total_tc,details:{passed:{qty},failed:{qty},...}}
|
|
addTestCaseToTestPlan |
devKey, testprojectid, testplanid, testcaseexternalid, version, platformid [required if plan has platforms], executionorder/urgency/overwrite [opt]
|
{operation,status,message,feature_id} |
Not live-verified: defines $messagePrefix at the top but every error branch in the body references undefined $msg_prefix instead - every error message in this method silently loses its prefix. |
addPlatformToTestPlan |
devKey, testplanid, platformname | result | Wraps private platformLinkOp(). |
removePlatformFromTestPlan |
devKey, testplanid, platformname | result | Same helper; refuses to unlink while test case versions on that platform are still linked to the plan. |
getTestSuitesForTestPlan |
devKey, testplanid | test suites, alphabetical | |
getExecCountersByBuild |
devKey, testplanid | {raw: full metrics, table: simplified per-build counts} |
| Method | Params | Returns | Notes |
|---|---|---|---|
createBuild |
devKey, testplanid, buildname, buildnotes/active/open/releasedate(YYYY-MM-DD)/copytestersfrombuild [all opt]
|
{status,id,message} |
If the build name already exists, returns the existing build's id with status:false rather than an error struct - check status, not just presence of id. |
closeBuild |
devKey, buildid | {id,status,operation,message} |
|
getBuildsForTestPlan |
devKey, testplanid | array of builds (or null) | |
getLatestBuildForTestPlan |
devKey, testplanid | single build struct / error TPLAN_HAS_NO_BUILDS
|
|
updateBuildCustomFieldsValues |
devKey, testprojectid, buildid, customfields (map) | array of {status,msg} per field |
Correctly returns after the full loop (contrast with the test-suite equivalent above). |
| Method | Params | Returns | Notes |
|---|---|---|---|
reportTCResult |
(see Test Cases table above) | ||
getLastExecutionResult |
devKey, tplanid, (testcaseid OR testcaseexternalid), platformid/platformname [opt], buildid/buildname [opt], options [opt: {getBugs:bool}]
|
execution map, or {id:-1} if never executed |
|
getAllExecutionsResults |
devKey, tplanid, (testcaseid OR testcaseexternalid), platform_id/build_id [opt], options [opt: {getBugs:bool}]
|
array of execution maps | |
getExecutionSet |
devKey, tplanid, (testcaseid OR testcaseexternalid), platformid/platformname [opt], buildid/buildname [opt], options [opt: {getOrderDescending:bool}]
|
all matching executions, ordered by id | Not just the latest - the full set. |
deleteExecution |
devKey, executionid |
{status,id,message} / error |
Requires exec_delete right. |
assignTestCaseExecutionTask / unassignTestCaseExecutionTask
|
(see Test Cases table above) | ||
getTestCaseAssignedTester |
(see Test Cases table above) |
| Method | Params | Returns | Notes |
|---|---|---|---|
getRequirements |
devKey, testprojectid, testplanid [opt], platformid [opt, only meaningful with testplanid]
|
array of requirements | Requires mgt_view_req. |
getRequirement |
devKey, testprojectid, (requirementid OR requirementdocid), version/requirementversionid [opt, default latest]
|
requirement version struct | |
getReqCoverage |
devKey, testprojectid, requirementversionid | array of covering test case versions | |
assignRequirements |
devKey, testcaseexternalid, testprojectid, requirements (array of {req_spec, requirements:[ids]}) |
{status,message} |
Uses latest versions of both requirement and test case. |
getTestCaseRequirements |
(see Test Cases table above) | ||
getReqSpecCustomFieldDesignValue |
devKey, customfieldname, testprojectid, reqspecid | value | |
getRequirementCustomFieldDesignValue |
devKey, customfieldname, testprojectid, requirementid | value | |
uploadRequirementAttachment |
(see Attachments table below) | ||
uploadRequirementSpecificationAttachment |
(see Attachments table below) |
All share the same shape: devKey, a parent-id field, then title/description [opt], filename, filetype, content (base64-encoded). All return {fk_id,fk_table,title,description,file_name,file_size,file_type} or an error map.
| Method | Parent id field | Right required |
|---|---|---|
uploadRequirementSpecificationAttachment |
reqspecid | (via generic checks) |
uploadRequirementAttachment |
requirementid | (via generic checks) |
uploadTestProjectAttachment |
testprojectid |
mgt_view_tc (an odd choice for an upload, but that's what the code checks) |
uploadTestSuiteAttachment |
testsuiteid | mgt_view_tc |
uploadTestCaseAttachment |
testcaseid + version |
mgt_modify_tc. Not live-verified: references an undefined $msgPrefix (function defines $msg_prefix) - cosmetic prefix loss only. |
uploadExecutionAttachment |
executionid | none beyond authenticate (a comment in the code itself questions this) |
uploadAttachment |
fkid + fktable (raw table name: nodes_hierarchy, tcversions, executions, req_specs, requirements, builds) |
generic low-level version all the above delegate to |
| Method | Params | Returns | Notes |
|---|---|---|---|
getTestCaseBugs |
(see Test Cases table above) | ||
getIssueTrackerSystem |
devKey, itsname | ITS struct / error ITS_NOT_FOUND
|
Requires issuetracker_view when called externally; internal callers (e.g. createTestProject) skip that check. |
| Issue | Method | Summary |
|---|---|---|
| #450 | createTestCase |
Duplicate external_id struct member from a malformed array literal (stray quote). |
| #451 | any zero-param method |
count(null) fatal in the shared IXR library on a spec-compliant empty <params> block. |
| #452 | setTestMode |
Swallowed its own error, returning bare false. |
| #453 | setUserRoleOnProject |
Unknown role showed the raw locale-key placeholder instead of a message. |
| #454 | getUserByLogin |
Non-admin cross-user lookup got a misleading "user not found" instead of a permission error. |
| #455 | getUserByID |
Same case fataled outright (undefined constant). |
| #456 | createPlatform |
Duplicate-name check was blind to platforms created with default-disabled design/execution flags. |
These came up while reading the source to write the tables above. None of them were reproduced against a running server, so treat them as leads for testing, not confirmed defects (the same way #450 started as a code-read observation before being traced and fixed).
-
Pervasive prefix-variable typo. Many methods declare their
error-message prefix as
$msg_prefix,$messagePrefix, or$msgPrefix- inconsistently - and then reference a different one of those three names elsewhere in the same function, which is undefined in that scope. Effect is always the same: that one error message silently loses its"(methodName) - "prefix (PHP 8 warning, not fatal). Confirmed instances:addTestCaseToTestPlan(throughout),getTestPlanPlatforms,uploadTestCaseAttachment,updateTestCaseGetTCVID(used byupdateTestCase),getTestCaseAssignedTester,setTestCaseTestSuite. This is the same bug class that caused #454 and #455 - those two happened to also break actual control flow (undefined variable used in a condition, or an undefined constant), which is why they got fixed; the ones listed here are purely cosmetic message loss. Worth a dedicated grep-and-fix pass rather than one-off patches. -
setTestCaseExecutionTypebuilt its "missing required parameter" message with the wrong param name (customfieldsinstead ofexecutiontype) - FIXED in #458, live-verified. -
platformLinkOp(private, backsaddPlatformToTestPlan/removePlatformFromTestPlan) hasif(! $tatus_ok)- missing thes. Reads alarmingly but is harmless: every success path already returns earlier through a separate check, so this line is only ever reached when the real$status_okis false anyway. -
updateTestSuiteCustomFieldDesignValuereturned from inside itsforeachloop over custom fields, so only the first field's result was ever reported even when multiple were passed in one call - FIXED in #460, live-verified (see Bugfix-Issue-460). -
getTestSuitebuilds its permission-check context from an undefined$dummyvariable (the loaded project is actually held in$tproj), so the real project id never reachesuserHasRight(); separately, its name-matching loop runs one index past the end of the results array ($ydx <= count($items)instead of<). -
checkPlatformIdentitypushes$platformInfointo$this->errors[]unconditionally on one code path, before it's known whether the call will actually fail - looks like leftover debug code. Low risk since$this->errorsis only returned to the client when the call fails.