Developers › API reference
Vendor & Contract Management
Base address https://vcm.kanishu.com/api/v1 · Download the OpenAPI description (for Postman, code generators and the like).
Conventions shared by every endpoint — tokens, headers, lists, safe retries, versions, limits — are in the developer guide; error codes are on Error codes. Each endpoint below names the scope a token needs.
Jump to: API access · People · Vendors
API access
POST /api/v1/api-access-requests
Create in api access requests
Request fields (JSON body)
allowed_ips | string (up to 2000), can be null | |
api_client_id | integer, can be null | |
purpose required | string (up to 1000) | |
scopes required | list of string | |
validity_days | integer: 30, 60, 90, can be null |
201 — Created. The record is in `data`; its address in `Location`.
GET /api/v1/api-access-requests/pending
Pending (api access requests pending)
| Parameter | In | Type | About |
|---|---|---|---|
fields | query | string | Only these fields of each record, comma-separated (e.g. `id,name`; nested: `owner.name`). `id` always comes back. |
200 — OK.
POST /api/v1/api-access-requests/{apiAccessRequest}/approve
Approve (api access requests approve)
| Parameter | In | Type | About |
|---|---|---|---|
apiAccessRequest required | path | integer |
200 — OK.
POST /api/v1/api-access-requests/{apiAccessRequest}/reject
Reject (api access requests reject)
| Parameter | In | Type | About |
|---|---|---|---|
apiAccessRequest required | path | integer |
Request fields (JSON body)
reason required | string (up to 500) |
200 — OK.
GET /api/v1/api-access-requests/{apiAccessRequest}/reveal
Reveal (api access requests reveal)
| Parameter | In | Type | About |
|---|---|---|---|
apiAccessRequest required | path | integer | |
fields | query | string | Only these fields of each record, comma-separated (e.g. `id,name`; nested: `owner.name`). `id` always comes back. |
200 — OK.
Reply fields (1)
token | string | The API token, shown this once. Store it in your secrets manager and send it as Authorization: Bearer <token>. |
Need fewer? Add ?fields= with the names you want, e.g. ?fields=token.
People
GET /api/v1/people
List people · scope people:read
| Parameter | In | Type | About |
|---|---|---|---|
page | query | integer | Page number, from 1. |
per_page | query | integer | Items a page (default 25, at most 100). |
fields | query | string | Only these fields of each record, comma-separated (e.g. `id,name`; nested: `owner.name`). `id` always comes back. |
200 — A page of results.
Reply fields (24) — each record in data
Also in the answer: meta, links.
id | string (uuid) | The person's id in People (a UUID). Use it with /people/{person}. |
display_name | string | The name shown everywhere in Kanishu. |
preferred_name | string, can be null | What they like to be called, if different. |
work_email | string | Their work email address; how they are matched to logins in the products. |
employee_number | string, can be null | Your own employee number for them (e.g. from payroll or HR). |
type | string | employee, contractor, external (auditor, consultant…) or other. |
status | string | pre_joining (joining soon), active, on_leave, leaving (last working day set) or left. |
joining_date | string (date), can be null | Their first working day. |
last_working_date | string (date), can be null | Their last working day, once they are leaving; their logins are switched off after it. |
access_end_date | string (date), can be null | When their access to Kanishu products ends, if earlier or later than the last working day (e.g. contractors). |
department | object, can be null | Their department or team (id and name), from GET /people-organisation. |
department.id | string (uuid) | |
department.name | string | |
position | object, can be null | Their job position (id and name). |
position.id | string (uuid) | |
position.name | string | |
location | object, can be null | Their office or site (id and name). |
location.id | string (uuid) | |
location.name | string | |
manager | object, can be null | Their manager in People (id and display_name). |
manager.id | string (uuid) | |
manager.display_name | string | |
created_at | string (date and time, ISO 8601) | |
updated_at | string (date and time, ISO 8601) |
Need fewer? Add ?fields= with the names you want, e.g. ?fields=display_name,preferred_name.
POST /api/v1/people
Create in people · scope people:write
Request fields (JSON body)
access_end_date | string (date), can be null | When their access to Kanishu products ends, if earlier or later than the last working day (e.g. contractors). |
display_name required | string (up to 255) | The name shown everywhere in Kanishu. |
employee_number | string (up to 50), can be null | Your own employee number for them (e.g. from payroll or HR). |
employment_status | string: pre_joining, active, on_leave, leaving, left | pre_joining (joining soon), active, on_leave, leaving (last working day set) or left. |
joining_date | string (date), can be null | Their first working day. |
location_id | string (uuid), can be null | |
manager_person_id | string (uuid), can be null | The manager's People id. |
org_unit_id | string (uuid), can be null | The department or team id, from GET /people-organisation. |
person_type | string: employee, contractor, external, other | employee, contractor, external (auditor, consultant…) or other. |
position_id | string (uuid), can be null | |
preferred_name | string (up to 255), can be null | What they like to be called, if different. |
work_email | string (email) (up to 255), can be null | Their work email address; how they are matched to logins in the products. |
201 — Created. The record is in `data`; its address in `Location`.
Reply fields (24) — in data
id | string (uuid) | The person's id in People (a UUID). Use it with /people/{person}. |
display_name | string | The name shown everywhere in Kanishu. |
preferred_name | string, can be null | What they like to be called, if different. |
work_email | string | Their work email address; how they are matched to logins in the products. |
employee_number | string, can be null | Your own employee number for them (e.g. from payroll or HR). |
type | string | employee, contractor, external (auditor, consultant…) or other. |
status | string | pre_joining (joining soon), active, on_leave, leaving (last working day set) or left. |
joining_date | string (date) | Their first working day. |
last_working_date | string (date), can be null | Their last working day, once they are leaving; their logins are switched off after it. |
access_end_date | string (date), can be null | When their access to Kanishu products ends, if earlier or later than the last working day (e.g. contractors). |
department | object | Their department or team (id and name), from GET /people-organisation. |
department.id | string (uuid) | |
department.name | string | |
position | object | Their job position (id and name). |
position.id | string (uuid) | |
position.name | string | |
location | object | Their office or site (id and name). |
location.id | string (uuid) | |
location.name | string | |
manager | object, can be null | Their manager in People (id and display_name). |
manager.id | string (uuid) | |
manager.display_name | string | |
created_at | string (date and time, ISO 8601) | |
updated_at | string (date and time, ISO 8601) |
GET /api/v1/people-organisation
Organisation (people organisation) · scope people:read
| Parameter | In | Type | About |
|---|---|---|---|
fields | query | string | Only these fields of each record, comma-separated (e.g. `id,name`; nested: `owner.name`). `id` always comes back. |
200 — OK. The record is in `data`, with its version in the `ETag` header.
Reply fields (18) — in data
departments | list | |
departments[].id | string (uuid) | |
departments[].name | string | |
departments[].type | string | What kind of unit it is (e.g. department, team, business unit). |
departments[].code | string | |
departments[].part_of_id | integer or string, can be null | The unit this one sits under, or null at the top. |
departments[].in_use | boolean | false when the unit is archived and no longer offered. |
positions | list | |
positions[].id | string (uuid) | |
positions[].name | string | |
positions[].code | string, can be null | |
positions[].in_use | boolean | false when the position is archived. |
locations | list | |
locations[].id | string (uuid) | |
locations[].name | string | |
locations[].code | string, can be null | |
locations[].city | string, can be null | |
locations[].in_use | boolean | false when the location is archived. |
Need fewer? Add ?fields= with the names you want, e.g. ?fields=departments,positions.
POST /api/v1/people/joiners
Add a joiner (from their start date) · scope people:write
Request fields (JSON body)
access | list of string, can be null | Logins they should get, as product key => role (e.g. {"itsm": "agent"}); each one waits for an approval. |
access_end_date | string (date), can be null | When their access to Kanishu products ends, if earlier or later than the last working day (e.g. contractors). |
display_name required | string (up to 255) | The name shown everywhere in Kanishu. |
employee_number | string (up to 50), can be null | Your own employee number for them (e.g. from payroll or HR). |
employment_status | string: pre_joining, active, on_leave, leaving, left | pre_joining (joining soon), active, on_leave, leaving (last working day set) or left. |
joining_date | string (date), can be null | Their first working day. |
location_id | string (uuid), can be null | |
manager_person_id | string (uuid), can be null | The manager's People id. |
org_unit_id | string (uuid), can be null | The department or team id, from GET /people-organisation. |
person_type | string: employee, contractor, external, other | employee, contractor, external (auditor, consultant…) or other. |
position_id | string (uuid), can be null | |
preferred_name | string (up to 255), can be null | What they like to be called, if different. |
start_date required | string (date) | Their first working day; their logins are prepared for it. |
work_email | string (email) (up to 255), can be null | Their work email address; how they are matched to logins in the products. |
201 — The new person, as GET /people/{person} returns them.
Reply fields (24) — in data
id | string (uuid) | The person's id in People (a UUID). Use it with /people/{person}. |
display_name | string | The name shown everywhere in Kanishu. |
preferred_name | string, can be null | What they like to be called, if different. |
work_email | string | Their work email address; how they are matched to logins in the products. |
employee_number | string, can be null | Your own employee number for them (e.g. from payroll or HR). |
type | string | employee, contractor, external (auditor, consultant…) or other. |
status | string | pre_joining (joining soon), active, on_leave, leaving (last working day set) or left. |
joining_date | string (date) | Their first working day. |
last_working_date | string (date), can be null | Their last working day, once they are leaving; their logins are switched off after it. |
access_end_date | string (date), can be null | When their access to Kanishu products ends, if earlier or later than the last working day (e.g. contractors). |
department | object | Their department or team (id and name), from GET /people-organisation. |
department.id | string (uuid) | |
department.name | string | |
position | object | Their job position (id and name). |
position.id | string (uuid) | |
position.name | string | |
location | object | Their office or site (id and name). |
location.id | string (uuid) | |
location.name | string | |
manager | object, can be null | Their manager in People (id and display_name). |
manager.id | string (uuid) | |
manager.display_name | string | |
created_at | string (date and time, ISO 8601) | |
updated_at | string (date and time, ISO 8601) |
GET /api/v1/people/{person}
Get one of people · scope people:read
| Parameter | In | Type | About |
|---|---|---|---|
person required | path | integer | |
fields | query | string | Only these fields of each record, comma-separated (e.g. `id,name`; nested: `owner.name`). `id` always comes back. |
200 — OK. The record is in `data`, with its version in the `ETag` header.
Reply fields (24) — in data
id | string (uuid) | The person's id in People (a UUID). Use it with /people/{person}. |
display_name | string | The name shown everywhere in Kanishu. |
preferred_name | string, can be null | What they like to be called, if different. |
work_email | string | Their work email address; how they are matched to logins in the products. |
employee_number | string, can be null | Your own employee number for them (e.g. from payroll or HR). |
type | string | employee, contractor, external (auditor, consultant…) or other. |
status | string | pre_joining (joining soon), active, on_leave, leaving (last working day set) or left. |
joining_date | string (date) | Their first working day. |
last_working_date | string (date), can be null | Their last working day, once they are leaving; their logins are switched off after it. |
access_end_date | string (date), can be null | When their access to Kanishu products ends, if earlier or later than the last working day (e.g. contractors). |
department | object | Their department or team (id and name), from GET /people-organisation. |
department.id | string (uuid) | |
department.name | string | |
position | object | Their job position (id and name). |
position.id | string (uuid) | |
position.name | string | |
location | object | Their office or site (id and name). |
location.id | string (uuid) | |
location.name | string | |
manager | object, can be null | Their manager in People (id and display_name). |
manager.id | string (uuid) | |
manager.display_name | string | |
created_at | string (date and time, ISO 8601) | |
updated_at | string (date and time, ISO 8601) |
Need fewer? Add ?fields= with the names you want, e.g. ?fields=display_name,preferred_name.
PATCH /api/v1/people/{person}
Change one of people · scope people:write
| Parameter | In | Type | About |
|---|---|---|---|
person required | path | integer |
Request fields (JSON body) — send only the fields you change
access_end_date | string (date), can be null | When their access to Kanishu products ends, if earlier or later than the last working day (e.g. contractors). |
display_name | string (up to 255) | The name shown everywhere in Kanishu. |
employee_number | string (up to 50), can be null | Your own employee number for them (e.g. from payroll or HR). |
employment_status | string: pre_joining, active, on_leave, leaving, left | pre_joining (joining soon), active, on_leave, leaving (last working day set) or left. |
joining_date | string (date), can be null | Their first working day. |
location_id | string (uuid), can be null | |
manager_person_id | string (uuid), can be null | The manager's People id. |
org_unit_id | string (uuid), can be null | The department or team id, from GET /people-organisation. |
person_type | string: employee, contractor, external, other | employee, contractor, external (auditor, consultant…) or other. |
position_id | string (uuid), can be null | |
preferred_name | string (up to 255), can be null | What they like to be called, if different. |
work_email | string (email) (up to 255), can be null | Their work email address; how they are matched to logins in the products. |
200 — OK. The record is in `data`, with its version in the `ETag` header.
Reply fields (24) — in data
id | string (uuid) | The person's id in People (a UUID). Use it with /people/{person}. |
display_name | string | The name shown everywhere in Kanishu. |
preferred_name | string, can be null | What they like to be called, if different. |
work_email | string | Their work email address; how they are matched to logins in the products. |
employee_number | string, can be null | Your own employee number for them (e.g. from payroll or HR). |
type | string | employee, contractor, external (auditor, consultant…) or other. |
status | string | pre_joining (joining soon), active, on_leave, leaving (last working day set) or left. |
joining_date | string (date) | Their first working day. |
last_working_date | string (date), can be null | Their last working day, once they are leaving; their logins are switched off after it. |
access_end_date | string (date), can be null | When their access to Kanishu products ends, if earlier or later than the last working day (e.g. contractors). |
department | object | Their department or team (id and name), from GET /people-organisation. |
department.id | string (uuid) | |
department.name | string | |
position | object | Their job position (id and name). |
position.id | string (uuid) | |
position.name | string | |
location | object | Their office or site (id and name). |
location.id | string (uuid) | |
location.name | string | |
manager | object, can be null | Their manager in People (id and display_name). |
manager.id | string (uuid) | |
manager.display_name | string | |
created_at | string (date and time, ISO 8601) | |
updated_at | string (date and time, ISO 8601) |
POST /api/v1/people/{person}/leave
Record a leaver (logins switched off after the last working day, or now if urgent) · scope people:write
| Parameter | In | Type | About |
|---|---|---|---|
person required | path | integer |
Request fields (JSON body)
last_working_date required | string (date) | Their last working day, once they are leaving; their logins are switched off after it. |
reason | string (up to 500), can be null | Why they are leaving (kept in People's History). |
urgent | boolean | true to switch their logins off now instead of after the last working day. |
200 — The person, as GET /people/{person} returns them.
Reply fields (24) — in data
id | string (uuid) | The person's id in People (a UUID). Use it with /people/{person}. |
display_name | string | The name shown everywhere in Kanishu. |
preferred_name | string, can be null | What they like to be called, if different. |
work_email | string | Their work email address; how they are matched to logins in the products. |
employee_number | string, can be null | Your own employee number for them (e.g. from payroll or HR). |
type | string | employee, contractor, external (auditor, consultant…) or other. |
status | string | pre_joining (joining soon), active, on_leave, leaving (last working day set) or left. |
joining_date | string (date) | Their first working day. |
last_working_date | string (date), can be null | Their last working day, once they are leaving; their logins are switched off after it. |
access_end_date | string (date), can be null | When their access to Kanishu products ends, if earlier or later than the last working day (e.g. contractors). |
department | object | Their department or team (id and name), from GET /people-organisation. |
department.id | string (uuid) | |
department.name | string | |
position | object | Their job position (id and name). |
position.id | string (uuid) | |
position.name | string | |
location | object | Their office or site (id and name). |
location.id | string (uuid) | |
location.name | string | |
manager | object, can be null | Their manager in People (id and display_name). |
manager.id | string (uuid) | |
manager.display_name | string | |
created_at | string (date and time, ISO 8601) | |
updated_at | string (date and time, ISO 8601) |
POST /api/v1/people/{person}/move
Move a person (department, manager, position or location) from a date · scope people:write
| Parameter | In | Type | About |
|---|---|---|---|
person required | path | integer |
Request fields (JSON body)
department_id | string (uuid), can be null | The department or team they move to, from GET /people-organisation. |
effective_date required | string (date) | The date the move takes effect. |
location_id | string (uuid), can be null | |
manager_id | string (uuid), can be null | Their new manager's People id. |
position_id | string (uuid), can be null |
200 — The person, as GET /people/{person} returns them.
Reply fields (24) — in data
id | string (uuid) | The person's id in People (a UUID). Use it with /people/{person}. |
display_name | string | The name shown everywhere in Kanishu. |
preferred_name | string, can be null | What they like to be called, if different. |
work_email | string | Their work email address; how they are matched to logins in the products. |
employee_number | string, can be null | Your own employee number for them (e.g. from payroll or HR). |
type | string | employee, contractor, external (auditor, consultant…) or other. |
status | string | pre_joining (joining soon), active, on_leave, leaving (last working day set) or left. |
joining_date | string (date) | Their first working day. |
last_working_date | string (date), can be null | Their last working day, once they are leaving; their logins are switched off after it. |
access_end_date | string (date), can be null | When their access to Kanishu products ends, if earlier or later than the last working day (e.g. contractors). |
department | object | Their department or team (id and name), from GET /people-organisation. |
department.id | string (uuid) | |
department.name | string | |
position | object | Their job position (id and name). |
position.id | string (uuid) | |
position.name | string | |
location | object | Their office or site (id and name). |
location.id | string (uuid) | |
location.name | string | |
manager | object, can be null | Their manager in People (id and display_name). |
manager.id | string (uuid) | |
manager.display_name | string | |
created_at | string (date and time, ISO 8601) | |
updated_at | string (date and time, ISO 8601) |
Vendors
GET /api/v1/vendors
List vendors · scope vendors:read
| Parameter | In | Type | About |
|---|---|---|---|
page | query | integer | Page number, from 1. |
per_page | query | integer | Items a page (default 25, at most 100). |
q | query | string | Search text. |
filter[status] | query | string | Only records with this value; several values comma-separated mean "any of". |
filter[category] | query | string | Only records with this value; several values comma-separated mean "any of". |
sort | query | string | Comma-separated; prefix - for descending. Allowed: name, created_at, updated_at. Default: name. |
fields | query | string | Only these fields of each record, comma-separated (e.g. `id,name`; nested: `owner.name`). `id` always comes back. |
include | query | string | Related records in the same answer, comma-separated: `contracts` — The vendor's contracts: id, title, contract_number, status, total_value, currency, effective_date, expiration_date, auto_renewal, notice_period_days (needs `vendors:read`); `contacts` — The vendor's contacts: id, name, title, email, phone, is_primary (needs `vendors:read`). |
200 — A page of results.
Reply fields (23) — each record in data
Also in the answer: meta, links.
id | integer | |
name | string | |
category | string, can be null | |
status | string | pending (being onboarded), active, suspended or offboarded. |
gstin | string, can be null | The vendor's GST identification number (India). |
contracts | list | Only with ?include=contracts. The vendor's contracts: id, title, contract_number, status, total_value, currency, effective_date, expiration_date, auto_renewal, notice_period_days. |
contracts[].id | integer | |
contracts[].title | string | |
contracts[].contract_number | string | |
contracts[].status | string | draft, active, expired or terminated. |
contracts[].total_value | string | |
contracts[].currency | string | |
contracts[].effective_date | string (date) | |
contracts[].expiration_date | string (date) | |
contracts[].auto_renewal | boolean | true when the contract renews itself unless cancelled. |
contracts[].notice_period_days | integer | Days of notice needed to cancel or not renew. |
contacts | list | Only with ?include=contacts. The vendor's contacts: id, name, title, email, phone, is_primary. |
contacts[].id | integer | |
contacts[].name | string | |
contacts[].title | string | |
contacts[].email | string | |
contacts[].phone | string | |
contacts[].is_primary | boolean | true for the vendor's main contact. |
Need fewer? Add ?fields= with the names you want, e.g. ?fields=name,category.
GET /api/v1/vendors/audit-feed
Audit Feed (vendors audit feed) · scope vendors:audit-read
| Parameter | In | Type | About |
|---|---|---|---|
page_size | query | integer | Answer in pages of this many records (10–2000). Without it, everything comes back at once. |
after | query | integer | The `meta.next_after` from the previous page (start with 0). |
fields | query | string | Only these fields of each record, comma-separated (e.g. `id,name`; nested: `owner.name`). `id` always comes back. |
200 — Records in id order. With page_size, `meta.next_after` is the `after` for the next page (null on the last).
Reply fields (19) — each record in data
Also in the answer: meta.
id | integer | |
name | string | |
status | string | pending (being onboarded), active, suspended or offboarded. |
onboarding | object, can be null | Onboarding checklist status and the required items still missing (audit feed). |
onboarding.status | string | |
onboarding.missing_required | list | |
gst_registrations | list | |
gst_registrations[].gstin | string | |
gst_registrations[].state | string | |
gst_registrations[].status | string | |
contracts | list | |
contracts[].id | integer | |
contracts[].title | string | |
contracts[].status | string | draft, active, expired or terminated. |
contracts[].expiration_date | string (date) | |
contracts[].auto_renewal | boolean | true when the contract renews itself unless cancelled. |
flags | list | Things an auditor should look at (audit feed). |
document_types | list | The kinds of compliance documents on file (audit feed). |
last_assessed_at | string (date and time, ISO 8601), can be null | When the risk was last reassessed. |
Need fewer? Add ?fields= with the names you want, e.g. ?fields=name,status.
POST /api/v1/vendors/import
Import (vendors import) · scope vendors:write
Request fields (JSON body)
category | string (up to 255), can be null | |
contact_email | string (email) (up to 255), can be null | |
contact_name | string (up to 255), can be null | |
contact_phone | string (up to 50), can be null | |
name required | string (up to 255) | |
organization_id required | integer | Your organisation's id. |
200 — OK.
Reply fields (1)
id | integer |
GET /api/v1/vendors/{vendorId}
Get one of vendors · scope vendors:read
| Parameter | In | Type | About |
|---|---|---|---|
vendorId required | path | integer | |
fields | query | string | Only these fields of each record, comma-separated (e.g. `id,name`; nested: `owner.name`). `id` always comes back. |
200 — OK.
Reply fields (19)
id | integer | |
name | string | |
status | string | pending (being onboarded), active, suspended or offboarded. |
tier | string | strategic, preferred or standard. |
category | string | |
active_contract | object | The vendor's current active contract, or null. |
active_contract.title | string | |
active_contract.expiration_date | string (date) | |
active_contract.auto_renewal | boolean | |
active_contract.currency | string | |
active_contract.total_value | string | |
risk | object | The vendor's current risk: score (0–100), band (Low, Medium, High, Critical) and the factors behind it. |
risk.score | integer | |
risk.band | string | |
risk.factors | list | Reasons that added to the score. |
performance | object | Survey ratings and open issues for the vendor. |
performance.average_survey_rating | integer | |
performance.survey_count | integer | |
performance.open_issue_count | integer |
Need fewer? Add ?fields= with the names you want, e.g. ?fields=name,status.