Skip to content

Read one request's approval trail (user)

The whole approval trail for one request: where it got to, and how it got there.

progress is the ladder as it stands now - the same block the queues and the own-requests feed carry. history is what happened: every approval, rejection, restart and administrative close, with who acted and at which step.

Fetched per request rather than shipped with every row of a list, because a list nobody drills into would pay for the history of every entry, and both halves are wanted together exactly when somebody opens one request. It is also the only way to explain a settled request: once decided, a request drops out of every queue.

Readable by the request's own employee and by anyone its chain asks to decide it. Anybody else gets 403.

HTTP: bearerAuth

User bearer token. Default authentication for customer-facing endpoints. Obtain a token by calling POST /login with your credentials, then send it on every subsequent request as Authorization: Bearer <token>. The token inherits the permissions and PBX scope of the authenticated user.

HTTP Authorization Scheme
bearer
Bearer format
Bearer <token>
pbx path · string · uuid *
UUID of the PBX tenant. Must be the tenant the token belongs to; anything else is refused with 403 rather than answered from another tenant.
kind path · string *
Which kind of request the id names. The same three values the pending queues use, and the same `kind` each queue entry carries, so a client passes back what it was given. Required rather than inferred: absence and home office requests share one table, so an id alone cannot say which of the two it is. A path whose kind does not match the row returns 404 rather than answering about the other type.
enum: absences home-office time-point-corrections
id path · string · uuid *
UUID of the request, as returned by the queues and the own-requests feed.
accept header · string
example: application/json

Responses

OK. The request's status, its current progress and its audit trail. `progress: null` with an empty `history` is a valid and meaningful answer, not an error: it means nobody was ever asked. A request created already approved by an admin, or raised before approval chains existed and never given v1 rows, looks like this. Read `status` for the outcome and show "no approval chain applied" rather than an empty ladder.
Response schema
kind*string
enum: absences home-office time-point-corrections
example: absences
id*string · uuid
example: 550e8400-e29b-41d4-a716-446655440010
status*string | null
The request's own status. Included because the other two fields cannot always answer "so what happened": a request settled without any approval flow has a null `progress` and an empty `history`, and without this the payload would say nothing about the outcome.
example: approved
progress*object | null
Where a request stands in its approval chain: how far it has got, who moved it, and who it is waiting on. **Null when nobody was ever asked** - a request created already approved by an admin, or raised before approval chains existed and never given v1 rows. That is not the same as a chain waiting on nobody, which is an empty `waiting_on` on a real ladder. Read the request's own status for the outcome in that case, and show "no approval chain applied" rather than a ladder of zeroes. A request decided by the older v1 engine DOES get a block: it has no steps, so the ladder is empty, but `legacy` is true and `approved_by` names who answered. Names are the ones frozen on each approval row when it was written, so a validator who has since been deleted still reads correctly.
current_stepstring | null
The name of the step holding the request, or null when no step is active - either because it is settled or because there is no chain.
example: Team lead
steps_total*integer
How many steps this request's chain holds.
example: 3
steps_done*integer
How many of them are completed. With `steps_total` this is the "2 of 3" a status display shows.
example: 1
legacy*boolean
True for a request raised before approval chains existed. Worth reading: such a request has no steps and would otherwise look unconfigured rather than like an older one finishing where it started.
example:
waiting_on*array<object>
The validators still to answer at the step currently holding the request. Only that step: earlier ones are settled and later ones have not been asked. On a request decided by validator rules (`legacy: true`), every validator who has not answered yet. Empty on a settled request. One entry per person.
employee_id*string | null · uuid
The validator's employee id. Compare it with your own to tell whether the request waits on you.
example: 550e8400-e29b-41d4-a716-446655440031
name*string
Display name, frozen on the approval row when it was written.
example: Muller Jonas
approved_by*array<object>
Everyone who has approved so far, across every step and the supervisors. One entry per person.
employee_id*string | null · uuid
The approver's employee id.
example: 550e8400-e29b-41d4-a716-446655440030
name*string
Display name, frozen on the approval row when it was written.
example: Lemaire Farid
next_stepobject | null
The step that will be asked once the current one completes, or null when this is the last one. Lets a client say what happens next rather than only what is happening.
labelstring
example: HR
orderinteger
example: 2
steps*array<object>
The whole ladder, in the order it is asked.
orderinteger
This step's place in the chain, counting from 1.
example: 1
labelstring
The step's name, or a generated "Step n" when the chain left it unnamed.
example: Team lead
statusstring
`active` holds the request; `pending` has not been reached; `bypassed` was skipped, either because nobody on it covers this request type or because the request was settled above it.
enum: pending active completed bypassed rejected
example: completed
status_labelstring | null
The status as a sentence, already translated.
example: Approved by Lemaire Farid
passed_overboolean
Completed with nobody on this step answering - a supervisor settled the request, or an admin closed the chain. Worth drawing differently from a real approval.
example:
requiredinteger
How many approvals this step needs before it completes.
example: 1
approvedinteger
How many it has.
example: 1
validatorsarray<object>
employee_idstring | null · uuid
The validator's employee id.
example: 550e8400-e29b-41d4-a716-446655440030
namestring
example: Lemaire Farid
statusstring
enum: pending accepted rejected
example: accepted
mandatoryboolean
Their approval is required for the step to complete, whatever its quorum.
example:
supervisors*array<object>
People on the chain outside the ladder: told about the request, and where granted the power, able to settle it at any point. v1 calls these supervisors.
employee_idstring | null · uuid
The supervisor's employee id.
example: 550e8400-e29b-41d4-a716-446655440032
namestring
example: Weber Ines
statusstring
enum: pending accepted rejected
example: pending
can_decideboolean
Whether they may settle the request outright.
example: 1
history*array<object>
What actually happened to a request, newest last: each approval, rejection, restart and administrative close, with who did it and where in the chain. Presentation is the client's business, so this carries no i18n block and no icon names - the admin panel's own renderer takes those from a separate source. `headline` is a translated sentence because it has to name people and steps the client does not otherwise have in hand; `tone` is the one word a client needs to colour the row.
atstring | null
When it happened, to the minute.
example: 2026-03-02 09:14
actionstring | null
The stored action name, for a client that wants to branch on it.
example: approved
tonestring | null
The shape of the event in one word, so a row can be coloured without knowing every action name.
example: positive
headlinestring | null
The event as a translated sentence.
example: Lemaire Farid approved at Team lead
actorstring | null
Who acted, as their name was recorded at the time - so somebody since deleted still reads correctly. Null for an event the system raised.
example: Lemaire Farid
stepstring | null
Which step it happened at, when the event belongs to one.
example: Team lead
commentstring | null
example: Fine by me
supersededarray<object>
On a restart, the answers it replaced. Those rows are no longer the live round, so this is the only place they read back.
namestring
example: Weber Ines
statusstring
example: accepted
Authorization Token Missing. This error is returned when the authorization token is missing.
Response schema
errorstring
Error message
example: Authorization Token is missing
Forbidden. You are neither the requester nor somebody this request asks.
Response schema
No response body.
Not found. No such request in this tenant, or its kind does not match the path - an absence path cannot reach a home office request even though they share a table.
Response schema
No response body.
get https://cockpit.voxbi.com/api/v1/v2/{pbx}/requests/{kind}/{id}/trail
Base URL
Request sample
curl -X GET 'https://cockpit.voxbi.com/api/v1/v2/{pbx}/requests/{kind}/{id}/trail' \
  -H 'Authorization: Bearer YOUR_TOKEN'
const response = await fetch('https://cockpit.voxbi.com/api/v1/v2/{pbx}/requests/{kind}/{id}/trail', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${YOUR_TOKEN}`,
  },
});

const data = await response.json();
console.log(data);
import requests

response = requests.get('https://cockpit.voxbi.com/api/v1/v2/{pbx}/requests/{kind}/{id}/trail',
    headers={'Authorization': f'Bearer {YOUR_TOKEN}'}
)
response.raise_for_status()
data = response.json()
print(data)
<?php
$context = stream_context_create([
    'http' => [
        'method'  => 'GET',
        'header'  => "Content-Type: application/json\r\nAuthorization: Bearer YOUR_TOKEN",
    ],
]);

$response = file_get_contents('https://cockpit.voxbi.com/api/v1/v2/{pbx}/requests/{kind}/{id}/trail', false, $context);
$data = json_decode($response, true);
print_r($data);
No example for this status.
{ … }
"error": "Authorization Token is missing"
}
Cache-Control string
example: private, must-revalidate
Connection string
example: keep-alive
Content-Type string
example: application/json
Vary string
example: Origin
X-RateLimit-Limit integer
Max requests allowed in the current rate-limit window.
example: 60
X-RateLimit-Remaining integer
Requests remaining in the current rate-limit window.
example: 57
No example for this status.
No example for this status.