Skip to content

Record your decision on one request (user)

Approve or reject one request, whatever its kind.

One route for all three kinds, where v1 has a separate endpoint per type with a different body for each. The engine underneath is unchanged, so a decision taken here settles exactly as one taken on v1 does - including any single rejection ending the request outright, from any step.

The response carries the request's status and progress after the decision, so a client can redraw the row without a second call, and can tell "recorded, still waiting on others" from "that settled it" - which a bare 201 cannot say.

Refusals are distinguished on purpose:

  • 403 you are not among the people this request asks to decide it.
  • 409 with a step message: the request has not reached your step yet. Matches the can_decide_now: false the queues report for that row.
  • 409 with a pending message: you already answered, or somebody settled it first. A race lost honestly, not a permissions problem.
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

Request body · required · application/json

Request schema
status*string
enum: accepted rejected
example: accepted
commentstring | null
Optional note, shown to the requester and kept on the trail.
length: 0–1000
example: Fine by me

Responses

Created. Your decision is recorded.
Response schema
kind*string
enum: absences home-office time-point-corrections
example: absences
id*string · uuid
example: 550e8400-e29b-41d4-a716-446655440010
status*string
The request's own status after your decision. Still pending when the chain needs more answers.
example: pending
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
Bad request. The request is no longer pending.
Response schema
No response body.
Authorization Token Missing. This error is returned when the authorization token is missing.
Response schema
errorstring
Error message
example: Authorization Token is missing
Forbidden. This request does not ask you to decide it.
Response schema
No response body.
Not found, or its kind does not match the path.
Response schema
No response body.
Conflict. Either the chain has not reached your step, or the request was already decided - by you, or by somebody who got there first.
Response schema
No response body.
Unprocessable Parameters. This error is returned when a parameter is not valid.
Response schema
messagestring
example: The given data was invalid.
errorsobject
filterarray<string>
[]string
sortarray<string>
[]string
pagearray<string>
[]string
per_pagearray<string>
[]string
post https://cockpit.voxbi.com/api/v1/v2/{pbx}/requests/{kind}/{id}/decision
Base URL
Request sample
curl -X POST 'https://cockpit.voxbi.com/api/v1/v2/{pbx}/requests/{kind}/{id}/decision' \
  -H 'Authorization: Bearer YOUR_TOKEN'
const response = await fetch('https://cockpit.voxbi.com/api/v1/v2/{pbx}/requests/{kind}/{id}/decision', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${YOUR_TOKEN}`,
  },
});

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

response = requests.post('https://cockpit.voxbi.com/api/v1/v2/{pbx}/requests/{kind}/{id}/decision',
    headers={'Authorization': f'Bearer {YOUR_TOKEN}'}
)
response.raise_for_status()
data = response.json()
print(data)
<?php
$context = stream_context_create([
    'http' => [
        'method'  => 'POST',
        '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}/decision', false, $context);
$data = json_decode($response, true);
print_r($data);
Sample request
No request example provided.
No example for this status.
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.
No example for this status.
{ … }
"errors": { … }
"filter": [ … ],
"The filter field must be an array."
],
"sort": [ … ],
"The sort field must be a string."
],
"page": [ … ],
"The page field must be an integer."
],
"per_page": [ … ]
"The per page field must be an integer."
]
}
}
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