Guies
Primers passos
El mateix recorregut que el tutorial «Comença amb l'API pas a pas» de Desenvolupadors, per a qui programa. Crea una clau de proves (pt_test_…) amb permisos de només lectura, comprova la connexió, llegeix dades reals i, quan la integració estigui a punt, passa a una clau live amb els permisos justos. Els avisos automàtics (webhooks) i les escriptures requereixen el pla Developer o superior.
1. Crea una clau a «Les meves claus»
Tria l'entorn de proves i només permisos de lectura (per exemple budgets:read). La clau completa es mostra una sola vegada: desa-la en un gestor de contrasenyes i envia-la a la capçalera Authorization: Bearer.
2. Comprova la connexió
GET /api/v1/ping
Respon amb el nom de la clau, els seus permisos i l'entorn. Un 401 vol dir clau no vàlida; un 403, que falta un permís.
3. Llegeix les teves dades reals
GET /api/v1/budgets
?limit=3
Els llistats es paginen per cursor: repeteix la crida amb cursor=<next_cursor> fins que has_more sigui false. Cada resposta porta X-RateLimit-Remaining amb les peticions que queden a la finestra.
4. Rep avisos automàtics
POST /api/v1/webhooks
{ "url": "https://el-teu-sistema.com/avisos-del-taller", "events": ["lead.accepted", "vehicle.ready"] }També es creen des de la pestanya Webhooks sense programar. Desa el secret de signatura i verifica X-PT-Signature a cada lliurament; respon 2xx en menys de 5 segons.
5. Passa a producció
Abans, si vols, prova escriptures, acceptacions, factures i missatges sense risc a l'entorn de proves (https://demo.programa-taller.es/desarrolladores-sandbox): dades fictícies i res no surt de debò. Crea una clau live amb els permisos mínims i, si vas a escriure dades, afegeix Idempotency-Key a cada POST. Els límits i el pla d'API del taller es veuen a la pestanya Consum; els plans Developer i Business es contracten des del mateix programa.
Guia: crear un pressupost i proposar cita
Flux típic d'un CRM o d'una web de reserves. Totes les peticions POST porten Idempotency-Key (un UUID nou per operació; repeteix-lo només quan reintentis la mateixa). Necessites una clau live amb clients:write, vehicles:write, budgets:write, appointments:read i appointments:write.
1. Client: crear-lo o recuperar l'existent
POST /api/v1/clients
{ "name": "Laura Gómez", "phone": "600111222", "email": "laura@ejemplo.com" }Amb ?on_conflict=return_existing, si el telèfon, l'email o el NIF ja existeixen reps aquest client (200) en lloc de 409.
2. Vehicle del client
POST /api/v1/vehicles
{ "client_id": 1204, "plate": "1234KLM", "brand": "Seat", "model": "León" }Si la matrícula és d'un altre client: 409 vehicle_belongs_to_other_client (decideix el taller).
3. Pressupost amb les seves partides
POST /api/v1/budgets
{ "client_id": 1204, "vehicle_id": 871, "lines": [{ "description": "Canvi d'oli i filtre", "quantity": 1, "unit_price": 65 }] }La resposta porta els totals calculats. El client accepta i signa des de l'enllaç que li envia el taller (l'API no dona mai aquest enllaç); si t'ho confirma a tu per una altra via, accepta'l en nom seu amb POST /budgets/{id}/accept (permís budgets:accept).
4. Forats lliures
GET /api/v1/appointments/availability
?from=2026-10-14&to=2026-10-18&duration_minutes=60
5. Proposar la cita
POST /api/v1/appointments
{ "budget_id": 1234, "start": "2026-10-14T09:00:00+02:00", "duration_minutes": 60 }En mode «proposar» queda status=proposed fins que el taller la confirma (rebràs appointment.confirmed per webhook). Si el forat s'ha ocupat: 409 slot_unavailable amb alternatives.
Guia: el teu bot o IA als canals del taller
El teu assistent contesta per WhatsApp, SMS, xat web o correu en lloc de l'assistent del programa. Necessites una clau live amb communications:read, messages:send, settings:write i webhooks:manage (pla Business o Partner). Prova-ho abans a l'entorn de proves amb POST /sandbox/simulate/message.
1. Subscriu-te a message.received
POST /api/v1/webhooks
{ "url": "https://el-teu-bot.com/taller", "events": ["message.received"] }Cada missatge del client arriba signat amb la clau de la conversa (key), el client, el pressupost actiu, el text i els adjunts.
2. Activa el mode assistent extern
PUT /api/v1/settings/assistant
{ "external_channels": ["whatsapp", "chat"], "fallback_minutes": 10 }En aquests canals l'assistent del programa deixa de contestar. Si no respons a temps, o la teva clau o el teu webhook deixen de funcionar, torna a contestar ell a aquest missatge.
3. Llegeix el fil si ho necessites
GET /api/v1/conversations/{key}/messages
4. Respon
POST /api/v1/conversations/{key}/messages
{ "text": "Demà a les 9:00 tenim lloc. Te la reservo?" }Fora de la finestra de 24 h de WhatsApp envia template_id (GET /messages/templates). Per tancar la venda: POST /appointments, POST /budgets/{id}/accept o POST /budgets/{id}/invoice segons els teus permisos.
Guia: flotes i rènting amb una clau de client
Perquè una flota, una empresa de rènting o un client amb molts vehicles connecti els seus sistemes amb el taller sense veure les dades dels altres clients, el taller li crea una clau limitada a la seva fitxa de client («Limitar a un client» en crear-la a Les meves claus). Amb ella cada llistat retorna només les seves dades, un id d'un altre client respon 404, les operacions de tot el taller responen 403 client_key_forbidden i els seus webhooks només reben els seus esdeveniments.
1. Comprova a quin client està limitada
GET /api/v1/ping
key.client porta l'id i el nom del client; en una clau del taller és null.
2. Els seus vehicles
GET /api/v1/vehicles
?limit=200
Només surten els vehicles de la seva fitxa. Per donar-ne d'alta un de nou, POST /vehicles amb el seu propi client_id.
3. Demanar un pressupost
POST /api/v1/budgets
{ "client_id": 1204, "vehicle_id": 871, "public_notes": "Revisió dels 60.000 km" }client_id ha de ser el de la clau (si no, 403 client_key_forbidden). El taller el completa i l'envia; la flota l'accepta o el rebutja amb POST /budgets/{id}/accept o /reject (permís budgets:accept).
4. Proposar cita i seguir l'estat
POST /api/v1/appointments
{ "budget_id": 1234, "start": "2026-10-20T09:00:00+02:00", "duration_minutes": 60 }Subscriu un webhook a lead.status_changed, vehicle.ready i invoice.issued per assabentar-te'n al moment; només arribaran els dels seus vehicles.
Entorn de proves
https://demo.programa-taller.es és una instància amb dades fictícies que es restauren cada 2 hores. Qualsevol clau d'allà és de proves amb tots els permisos: pot escriure, acceptar, facturar i «enviar», però res no surt de debò (els enviaments es registren com a simulats) i els webhooks s'emeten igualment per provar el cicle complet. Les teves claus, webhooks i registre de peticions es conserven entre reinicis.
1. Demana la teva clau
POST /api/v1/sandbox/keys
{ "email": "dev@exemple.com", "company": "Integracions Exemple SL", "name": "Anna Puig" }També des de la pàgina https://demo.programa-taller.es/desarrolladores-sandbox. La clau es mostra una sola vegada i val 30 dies.
2. Simula un client que escriu
POST /api/v1/sandbox/simulate/message
{ "channel": "whatsapp", "from": "+34600111222", "text": "Teniu lloc demà?" }3. Canvia a producció
Canvia la URL base per la de la instància del taller i fes servir una clau live creada a la seva secció Desenvolupadors.
Clients
GET /api/v1/clients clients:read
Llistar clients
Ordenats per id ascendent. Els clients esborrats per RGPD apareixen anonimitzats, amb erased_at informat.
Permís necessari: clients:read.
Clau de client: només retorna o crea dades del seu client.
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
search | string | No | Cerca al nom, telèfon, email i NIF/CIF (mínim 2 caràcters). |
expand | string [vehicles] | No | Relacions opcionals que cal incloure. |
limit | integer · default 50 | No | Resultats per pàgina (1–200). |
cursor | string | No | Cursor opac retornat a next_cursor de la pàgina anterior. |
Exemple
curl "https://el-teu-taller.example/api/v1/clients" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"data": [
{
"id": 1204,
"name": "Laura Gómez",
"phone": "+34600111222",
"phone_secondary": null,
"whatsapp_phone": null,
"email": "laura@ejemplo.com",
"billing_email": null,
"tax_id": "12345678Z",
"address": "C/ Mayor 12",
"city": "Barcelona",
"zip": "08001",
"province": "Barcelona",
"country": "ES",
"preferred_language": "es",
"preferred_contact_method": "whatsapp",
"vip": false,
"marketing_opt_out": false,
"channel_opt_out": {
"email": false,
"sms": false,
"whatsapp": false,
"call": false
},
"erased_at": null,
"vehicles": [
{
"id": 871,
"client_id": 1204,
"client": null,
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"km": 84500,
"itv_expiry_date": "2027-03-15",
"status": "activo"
}
]
}
],
"next_cursor": "aWQ6MTIzNA",
"has_more": true
}
POST /api/v1/clients clients:write
Crear un client
Mai no fusiona amb una fitxa existent: si el NIF/CIF, l'email o el telèfon ja són en un altre client respon 409 client_exists amb existing_id (o 200 amb aquest client si passes ?on_conflict=return_existing). El telèfon es desa com a la fitxa (Espanya en 9 dígits, altres països amb prefix) i l'email en minúscules; no es corregeixen errades. Les baixes comercials queden al registre de consentiments.
Permís necessari: clients:write.
Clau de client: no disponible (403 client_key_forbidden).
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
on_conflict | string [error, return_existing] · default error | No | error (per defecte): 409 si ja existeix. return_existing: 200 amb el client existent. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"name": "Laura Gómez",
"phone": "600111222",
"phone_secondary": null,
"email": "laura@ejemplo.com",
"billing_email": null,
"tax_id": "12345678Z",
"address": "C/ Mayor 12",
"city": "Barcelona",
"zip": "08001",
"province": "Barcelona",
"country": "ES",
"preferred_language": "es",
"preferred_contact_method": "whatsapp",
"marketing_opt_out": false,
"channel_opt_out": {
"email": false,
"sms": false,
"whatsapp": false,
"call": false
}
}
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/clients" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"name":"Laura Gómez","phone":"600111222","phone_secondary":null,"email":"laura@ejemplo.com","billing_email":null,"tax_id":"12345678Z","address":"C/ Mayor 12","city":"Barcelona","zip":"08001","province":"Barcelona","country":"ES","preferred_language":"es","preferred_contact_method":"whatsapp","marketing_opt_out":false,"channel_opt_out":{"email":false,"sms":false,"whatsapp":false,"call":false}}'
Resposta
{
"id": 1204,
"name": "Laura Gómez",
"phone": "+34600111222",
"phone_secondary": null,
"whatsapp_phone": null,
"email": "laura@ejemplo.com",
"billing_email": null,
"tax_id": "12345678Z",
"address": "C/ Mayor 12",
"city": "Barcelona",
"zip": "08001",
"province": "Barcelona",
"country": "ES",
"preferred_language": "es",
"preferred_contact_method": "whatsapp",
"vip": false,
"marketing_opt_out": false,
"channel_opt_out": {
"email": false,
"sms": false,
"whatsapp": false,
"call": false
},
"erased_at": null,
"vehicles": [
{
"id": 871,
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"km": 84500,
"itv_expiry_date": "2027-03-15",
"status": "activo"
}
]
}
GET /api/v1/clients/{id} clients:read
Detall d'un client
Permís necessari: clients:read.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del client. |
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
expand | string [vehicles] | No | Relacions opcionals que cal incloure. |
Exemple
curl "https://el-teu-taller.example/api/v1/clients/1234" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"id": 1204,
"name": "Laura Gómez",
"phone": "+34600111222",
"phone_secondary": null,
"whatsapp_phone": null,
"email": "laura@ejemplo.com",
"billing_email": null,
"tax_id": "12345678Z",
"address": "C/ Mayor 12",
"city": "Barcelona",
"zip": "08001",
"province": "Barcelona",
"country": "ES",
"preferred_language": "es",
"preferred_contact_method": "whatsapp",
"vip": false,
"marketing_opt_out": false,
"channel_opt_out": {
"email": false,
"sms": false,
"whatsapp": false,
"call": false
},
"erased_at": null,
"vehicles": [
{
"id": 871,
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"km": 84500,
"itv_expiry_date": "2027-03-15",
"status": "activo"
}
]
}
PATCH /api/v1/clients/{id} clients:write
Modificar un client
Només canvien els camps enviats (null buida el camp). Es pot canviar l'email o el telèfon, i queda el valor anterior → nou a l'activitat del client amb el nom de la clau; emet client.updated. No es pot posar l'email, el telèfon o el NIF d'UNA ALTRA fitxa (409 client_exists). Les fitxes esborrades per RGPD responen 409 client_erased.
Permís necessari: clients:write.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del client. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | No | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"name": "Laura Gómez Ruiz",
"phone": "600111222",
"phone_secondary": null,
"email": "laura@ejemplo.com",
"billing_email": null,
"tax_id": "12345678Z",
"address": "C/ Mayor 12",
"city": "Barcelona",
"zip": "08001",
"province": "Barcelona",
"country": "ES",
"preferred_language": "es",
"preferred_contact_method": "whatsapp",
"marketing_opt_out": false,
"channel_opt_out": {
"email": false,
"sms": false,
"whatsapp": false,
"call": false
}
}
Exemple
curl -X PATCH "https://el-teu-taller.example/api/v1/clients/1234" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"name":"Laura Gómez Ruiz","phone":"600111222","phone_secondary":null,"email":"laura@ejemplo.com","billing_email":null,"tax_id":"12345678Z","address":"C/ Mayor 12","city":"Barcelona","zip":"08001","province":"Barcelona","country":"ES","preferred_language":"es","preferred_contact_method":"whatsapp","marketing_opt_out":false,"channel_opt_out":{"email":false,"sms":false,"whatsapp":false,"call":false}}'
Resposta
{
"id": 1204,
"name": "Laura Gómez",
"phone": "+34600111222",
"phone_secondary": null,
"whatsapp_phone": null,
"email": "laura@ejemplo.com",
"billing_email": null,
"tax_id": "12345678Z",
"address": "C/ Mayor 12",
"city": "Barcelona",
"zip": "08001",
"province": "Barcelona",
"country": "ES",
"preferred_language": "es",
"preferred_contact_method": "whatsapp",
"vip": false,
"marketing_opt_out": false,
"channel_opt_out": {
"email": false,
"sms": false,
"whatsapp": false,
"call": false
},
"erased_at": null,
"vehicles": [
{
"id": 871,
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"km": 84500,
"itv_expiry_date": "2027-03-15",
"status": "activo"
}
]
}
Vehicles
GET /api/v1/vehicles vehicles:read
Llistar vehicles
Inclou l'últim quilometratge anotat i el venciment de la ITV.
Permís necessari: vehicles:read.
Clau de client: només retorna o crea dades del seu client.
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
plate | string | No | Matrícula exacta (s'ignoren espais i guions). |
client_id | integer | No | Filtrar per client. |
status | string [activo, baja_temporal, baja] | No | Estat del vehicle. |
limit | integer · default 50 | No | Resultats per pàgina (1–200). |
cursor | string | No | Cursor opac retornat a next_cursor de la pàgina anterior. |
Exemple
curl "https://el-teu-taller.example/api/v1/vehicles" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"data": [
{
"id": 871,
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"km": 84500,
"itv_expiry_date": "2027-03-15",
"status": "activo"
}
],
"next_cursor": "aWQ6MTIzNA",
"has_more": true
}
POST /api/v1/vehicles vehicles:write
Donar d'alta un vehicle
Sempre a nom d'un client existent (client_id). La matrícula es normalitza (majúscules, sense espais ni guions). Si ja és a la fitxa d'UN ALTRE client: 409 vehicle_belongs_to_other_client. Si el mateix client ja la té: 409 vehicle_exists amb existing_id (o 200 amb ?on_conflict=return_existing).
Permís necessari: vehicles:write.
Clau de client: només retorna o crea dades del seu client.
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
on_conflict | string [error, return_existing] · default error | No | error (per defecte) o return_existing. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"client_id": 1204,
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"itv_expiry_date": "2027-03-15",
"status": "activo"
}
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/vehicles" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"client_id":1204,"plate":"1234 KLM","vin":"VSSZZZ5FZJR123456","brand":"Seat","model":"León","variant":"1.5 TSI","year":2019,"registration_date":"2019-03-15","fuel":"Gasolina","transmission":"Manual","engine_code":"DADA","horsepower":130,"displacement":"1498","color_code":null,"environmental_label":"C","itv_expiry_date":"2027-03-15","status":"activo"}'
Resposta
{
"id": 871,
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"km": 84500,
"itv_expiry_date": "2027-03-15",
"status": "activo"
}
GET /api/v1/vehicles/{id} vehicles:read
Detall d'un vehicle
Permís necessari: vehicles:read.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del vehicle. |
Exemple
curl "https://el-teu-taller.example/api/v1/vehicles/1234" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"id": 871,
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"km": 84500,
"itv_expiry_date": "2027-03-15",
"status": "activo"
}
PATCH /api/v1/vehicles/{id} vehicles:write
Modificar un vehicle
Canvis parcials. client_id no admet null: un vehicle mai no es desvincula del titular per API (sí que pot passar a un altre client existent).
Permís necessari: vehicles:write.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del vehicle. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | No | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"client_id": 1204,
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"itv_expiry_date": "2027-03-15",
"status": "activo"
}
Exemple
curl -X PATCH "https://el-teu-taller.example/api/v1/vehicles/1234" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"client_id":1204,"plate":"1234 KLM","vin":"VSSZZZ5FZJR123456","brand":"Seat","model":"León","variant":"1.5 TSI","year":2019,"registration_date":"2019-03-15","fuel":"Gasolina","transmission":"Manual","engine_code":"DADA","horsepower":130,"displacement":"1498","color_code":null,"environmental_label":"C","itv_expiry_date":"2027-03-15","status":"activo"}'
Resposta
{
"id": 871,
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"km": 84500,
"itv_expiry_date": "2027-03-15",
"status": "activo"
}
GET /api/v1/vehicles/{id}/history vehicles:read
Historial del vehicle
Visites al taller (tots els seus pressupostos tret dels d'ús intern, del més recent al més antic) amb estat, entrada i sortida, quilometratge, import, núm. de factura i conceptes de les partides; més les intervencions anotades en altres tallers. No inclou mai costos.
Permís necessari: vehicles:read.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del vehicle. |
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
limit | integer · default 50 | No | Màxim de visites (1–200). |
Exemple
curl "https://el-teu-taller.example/api/v1/vehicles/1234/history" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"vehicle": {
"id": 871,
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"plate": "1234 KLM",
"vin": "VSSZZZ5FZJR123456",
"brand": "Seat",
"model": "León",
"variant": "1.5 TSI",
"year": 2019,
"registration_date": "2019-03-15",
"fuel": "Gasolina",
"transmission": "Manual",
"engine_code": "DADA",
"horsepower": 130,
"displacement": "1498",
"color_code": null,
"environmental_label": "C",
"km": 84500,
"itv_expiry_date": "2027-03-15",
"status": "activo"
},
"visits": [
{
"budget_id": 1234,
"status": "Facturado",
"created_at": "2026-10-06T09:30:00.000Z",
"checked_in_at": "2026-09-02T07:30:00.000Z",
"delivered_at": "2026-09-03T16:00:00.000Z",
"km": 84210,
"amount": 245.3,
"invoice": "F26/118",
"category": "Mantenimiento",
"works": [
"Canvi d'oli i filtre"
]
}
],
"external_interventions": [
{
"title": "Canvi de pneumàtics",
"date": "2025-11-20",
"km": 78000,
"workshop_name": null,
"warranty_until": null
}
]
}
Pressupostos
GET /api/v1/budgets budgets:read
Llistar pressupostos
Mai no inclou els pressupostos d'ús intern del taller ni dades de cost. El detall (amb partides i totals) és a /budgets/{id}.
Permís necessari: budgets:read.
Clau de client: només retorna o crea dades del seu client.
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
status | string | No | Estat exacte, amb el valor en castellà (Pendiente, Enviado, Aprobado, Finalizado, Facturado, Rechazado…). |
client_id | integer | No | Filtrar per client. |
vehicle_id | integer | No | Filtrar per vehicle. |
from | string (date-time) | No | Creats a partir d'aquesta data. |
to | string (date-time) | No | Creats fins a aquesta data. |
updated_since | string (date-time) | No | Només registres modificats a partir d'aquesta data (ISO 8601). |
limit | integer · default 50 | No | Resultats per pàgina (1–200). |
cursor | string | No | Cursor opac retornat a next_cursor de la pàgina anterior. |
Exemple
curl "https://el-teu-taller.example/api/v1/budgets" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"data": [
{
"id": 1234,
"status": "Aprobado",
"created_at": "2026-10-06T09:30:00.000Z",
"updated_at": "2026-10-06T09:30:00.000Z",
"channel": "web",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"subcategory": {
"id": 5,
"name": "Mantenimiento"
},
"assigned_user": {
"id": 3,
"name": "Marta"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"appointment": {
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"status": "confirmed",
"client_confirmed_at": null,
"estimated_duration_minutes": 60,
"box": null
},
"date_in": null,
"date_out": null,
"km": 84500,
"client_reference": null,
"waiting_parts": false,
"on_hold": false,
"hold_until": null,
"client_signed_at": null,
"estimated_ready_at": null,
"delivered_at": null,
"reject_reason": null
}
],
"next_cursor": "aWQ6MTIzNA",
"has_more": true
}
POST /api/v1/budgets budgets:write
Crear un pressupost
Entra a «Pendiente» amb canal «API», igual que una alta des del programa (registre, fita d'obertura, webhook lead.created). Els totals es calculen al servidor amb l'impost del taller; si una partida no porta tax_rate, s'usa el del taller. El vehicle, si s'indica, ha de ser del client. No admet categories d'ús intern. Amb notify_client=true (i permís communications:send) s'envia al client l'acusament amb el seu enllaç de seguiment.
Permís necessari: budgets:write.
Clau de client: només retorna o crea dades del seu client.
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"client_id": 1204,
"vehicle_id": 871,
"category_id": 5,
"subcategory_id": 51,
"client_reference": "PED-2026-118",
"public_notes": "Revisar també el soroll de la suspensió.",
"lines": [
{
"description": "Canvi d'oli i filtre",
"quantity": 1,
"unit_price": 65,
"tax_rate": 21,
"discount_pct": 0,
"line_type": "labor",
"reference": null,
"group_title": null
}
],
"notify_client": false
}
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/budgets" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"client_id":1204,"vehicle_id":871,"category_id":5,"subcategory_id":51,"client_reference":"PED-2026-118","public_notes":"Revisar també el soroll de la suspensió.","lines":[{"description":"Canvi d'oli i filtre","quantity":1,"unit_price":65,"tax_rate":21,"discount_pct":0,"line_type":"labor","reference":null,"group_title":null}],"notify_client":false}'
Resposta
{
"id": 1234,
"status": "Aprobado",
"created_at": "2026-10-06T09:30:00.000Z",
"updated_at": "2026-10-06T09:30:00.000Z",
"channel": "web",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"subcategory": {
"id": 5,
"name": "Mantenimiento"
},
"assigned_user": {
"id": 3,
"name": "Marta"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"appointment": {
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"status": "confirmed",
"client_confirmed_at": null,
"estimated_duration_minutes": 60,
"box": {
"id": 2,
"name": "Elevador 2"
}
},
"date_in": null,
"date_out": null,
"km": 84500,
"client_reference": null,
"waiting_parts": false,
"on_hold": false,
"hold_until": null,
"client_signed_at": null,
"estimated_ready_at": null,
"delivered_at": null,
"reject_reason": null,
"public_notes": "Revisar també el soroll a la suspensió.",
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 5501,
"description": "Canvi d'oli i filtre",
"extended_detail": null,
"reference": null,
"line_type": "labor",
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"price_estimated": false,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
]
}
GET /api/v1/budgets/{id} budgets:read
Detall d'un pressupost
Partides (descripció, quantitat, preu unitari, impost, tipus, descompte), totals amb desglossament, cita, dates d'entrada i sortida, responsable i URL pública de seguiment.
Permís necessari: budgets:read.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del pressupost. |
Exemple
curl "https://el-teu-taller.example/api/v1/budgets/1234" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"id": 1234,
"status": "Aprobado",
"created_at": "2026-10-06T09:30:00.000Z",
"updated_at": "2026-10-06T09:30:00.000Z",
"channel": "web",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"subcategory": {
"id": 5,
"name": "Mantenimiento"
},
"assigned_user": {
"id": 3,
"name": "Marta"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"appointment": {
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"status": "confirmed",
"client_confirmed_at": null,
"estimated_duration_minutes": 60,
"box": {
"id": 2,
"name": "Elevador 2"
}
},
"date_in": null,
"date_out": null,
"km": 84500,
"client_reference": null,
"waiting_parts": false,
"on_hold": false,
"hold_until": null,
"client_signed_at": null,
"estimated_ready_at": null,
"delivered_at": null,
"reject_reason": null,
"public_notes": "Revisar també el soroll a la suspensió.",
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 5501,
"description": "Canvi d'oli i filtre",
"extended_detail": null,
"reference": null,
"line_type": "labor",
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"price_estimated": false,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
]
}
GET /api/v1/budgets/{id}/activity budgets:read
Historial del pressupost
El que ha passat al pressupost, del més recent al més antic: canvis d'estat, enviaments, acceptació (amb el seu origen), cites, missatges del client, facturació… El mateix registre que veu el taller a la fitxa; public=true marca el que també veu el client. Els codis d'un sol ús i els enllaços d'accés surten ocults.
Permís necessari: budgets:read.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del pressupost. |
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
visibility | string [all, public] · default all | No | all: tot el registre; public: només el que veu el client. |
limit | integer · default 50 | No | Resultats per pàgina (1–200). |
cursor | string | No | Cursor opac retornat a next_cursor de la pàgina anterior. |
Exemple
curl "https://el-teu-taller.example/api/v1/budgets/1234/activity" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"data": [
{
"id": 88123,
"at": "2026-10-06T09:30:00.000Z",
"event": "web_accepted",
"detail": "Pressupost acceptat pel client des de la web de seguiment",
"source": "client",
"public": true,
"user": {
"id": 3,
"name": "Marta"
}
}
],
"next_cursor": "aWQ6MTIzNA",
"has_more": true
}
POST /api/v1/budgets/{id}/lines budgets:write
Afegir una partida
La resta de partides conserven el seu id. Deixa instantània prèvia i registre com qualsevol edició del programa. 409 budget_locked si el pressupost és Facturado, Facturado externamente, Cancelado, Rechazado, Desistido o ja té factura.
Permís necessari: budgets:write.
Clau de client: no disponible (403 client_key_forbidden).
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del pressupost. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"description": "Canvi d'oli i filtre",
"quantity": 1,
"unit_price": 65,
"tax_rate": 21,
"discount_pct": 0,
"line_type": "labor",
"reference": null,
"group_title": null
}
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/budgets/1234/lines" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"description":"Canvi d'oli i filtre","quantity":1,"unit_price":65,"tax_rate":21,"discount_pct":0,"line_type":"labor","reference":null,"group_title":null}'
Resposta
{
"line": {
"id": 5501,
"description": "Canvi d'oli i filtre",
"extended_detail": null,
"reference": null,
"line_type": "labor",
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"price_estimated": false,
"base": 65,
"currency": "EUR",
"sort_order": 0
},
"budget": {
"id": 1234,
"status": "Aprobado",
"created_at": "2026-10-06T09:30:00.000Z",
"updated_at": "2026-10-06T09:30:00.000Z",
"channel": "web",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"subcategory": {
"id": 5,
"name": "Mantenimiento"
},
"assigned_user": {
"id": 3,
"name": "Marta"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"appointment": {
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"status": "confirmed",
"client_confirmed_at": null,
"estimated_duration_minutes": 60,
"box": {
"id": null,
"name": null
}
},
"date_in": null,
"date_out": null,
"km": 84500,
"client_reference": null,
"waiting_parts": false,
"on_hold": false,
"hold_until": null,
"client_signed_at": null,
"estimated_ready_at": null,
"delivered_at": null,
"reject_reason": null,
"public_notes": "Revisar també el soroll a la suspensió.",
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 5501,
"description": "Canvi d'oli i filtre",
"extended_detail": null,
"reference": null,
"line_type": "labor",
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"price_estimated": false,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
]
}
}
PATCH /api/v1/budgets/{id}/lines/{lineId} budgets:write
Modificar una partida
Permís necessari: budgets:write.
Clau de client: no disponible (403 client_key_forbidden).
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del pressupost. |
lineId | integer | Sí | Id de la partida. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | No | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"description": "Canvi d'oli i filtre",
"quantity": 1,
"unit_price": 65,
"tax_rate": 21,
"discount_pct": 0,
"line_type": "labor",
"reference": null,
"group_title": null
}
Exemple
curl -X PATCH "https://el-teu-taller.example/api/v1/budgets/1234/lines/5501" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"description":"Canvi d'oli i filtre","quantity":1,"unit_price":65,"tax_rate":21,"discount_pct":0,"line_type":"labor","reference":null,"group_title":null}'
Resposta
{
"line": {
"id": 5501,
"description": "Canvi d'oli i filtre",
"extended_detail": null,
"reference": null,
"line_type": "labor",
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"price_estimated": false,
"base": 65,
"currency": "EUR",
"sort_order": 0
},
"budget": {
"id": 1234,
"status": "Aprobado",
"created_at": "2026-10-06T09:30:00.000Z",
"updated_at": "2026-10-06T09:30:00.000Z",
"channel": "web",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"subcategory": {
"id": 5,
"name": "Mantenimiento"
},
"assigned_user": {
"id": 3,
"name": "Marta"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"appointment": {
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"status": "confirmed",
"client_confirmed_at": null,
"estimated_duration_minutes": 60,
"box": {
"id": null,
"name": null
}
},
"date_in": null,
"date_out": null,
"km": 84500,
"client_reference": null,
"waiting_parts": false,
"on_hold": false,
"hold_until": null,
"client_signed_at": null,
"estimated_ready_at": null,
"delivered_at": null,
"reject_reason": null,
"public_notes": "Revisar també el soroll a la suspensió.",
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 5501,
"description": "Canvi d'oli i filtre",
"extended_detail": null,
"reference": null,
"line_type": "labor",
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"price_estimated": false,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
]
}
}
DELETE /api/v1/budgets/{id}/lines/{lineId} budgets:write
Treure una partida
Retorna el pressupost amb els totals recalculats. La partida queda a la instantània prèvia de l'historial de versions.
Permís necessari: budgets:write.
Clau de client: no disponible (403 client_key_forbidden).
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del pressupost. |
lineId | integer | Sí | Id de la partida. |
Exemple
curl -X DELETE "https://el-teu-taller.example/api/v1/budgets/1234/lines/5501" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"id": 1234,
"status": "Aprobado",
"created_at": "2026-10-06T09:30:00.000Z",
"updated_at": "2026-10-06T09:30:00.000Z",
"channel": "web",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"subcategory": {
"id": 5,
"name": "Mantenimiento"
},
"assigned_user": {
"id": 3,
"name": "Marta"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"appointment": {
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"status": "confirmed",
"client_confirmed_at": null,
"estimated_duration_minutes": 60,
"box": {
"id": 2,
"name": "Elevador 2"
}
},
"date_in": null,
"date_out": null,
"km": 84500,
"client_reference": null,
"waiting_parts": false,
"on_hold": false,
"hold_until": null,
"client_signed_at": null,
"estimated_ready_at": null,
"delivered_at": null,
"reject_reason": null,
"public_notes": "Revisar també el soroll a la suspensió.",
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 5501,
"description": "Canvi d'oli i filtre",
"extended_detail": null,
"reference": null,
"line_type": "labor",
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"price_estimated": false,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
]
}
POST /api/v1/budgets/{id}/status budgets:write
Canviar l'estat
Admet Pendiente/En cotización/Enviado (abans de l'acceptació), En curso (pressupost ja acceptat), Finalizado (des d'Aprobado, En curso o En espera) i Cancelado. «Aprobado» respon 403 client_acceptance_required: l'acceptació la signa el client des de l'enllaç que li envia el taller, o la registra la teva integració en nom seu amb POST /budgets/{id}/accept (permís budgets:accept). Rebutjar va per POST /budgets/{id}/reject i facturar per POST /budgets/{id}/invoice (permís invoices:write); aquí responen 403 status_transition_forbidden, igual que desistir; des de Facturado o Cancelado, 409 budget_locked. «Enviado» exigeix a més communications:send i sent_via: registra que EL TEU sistema ja l'ha enviat (no l'envia). Cap canvi avisa el client excepte Finalizado amb notify_client=true i communications:send.
Permís necessari: budgets:write.
Clau de client: no disponible (403 client_key_forbidden).
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del pressupost. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"status": "En curso",
"sent_via": "email",
"notify_client": false
}
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/budgets/1234/status" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"status":"En curso","sent_via":"email","notify_client":false}'
Resposta
{
"id": 1234,
"status": "Aprobado",
"created_at": "2026-10-06T09:30:00.000Z",
"updated_at": "2026-10-06T09:30:00.000Z",
"channel": "web",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"subcategory": {
"id": 5,
"name": "Mantenimiento"
},
"assigned_user": {
"id": 3,
"name": "Marta"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"appointment": {
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"status": "confirmed",
"client_confirmed_at": null,
"estimated_duration_minutes": 60,
"box": {
"id": 2,
"name": "Elevador 2"
}
},
"date_in": null,
"date_out": null,
"km": 84500,
"client_reference": null,
"waiting_parts": false,
"on_hold": false,
"hold_until": null,
"client_signed_at": null,
"estimated_ready_at": null,
"delivered_at": null,
"reject_reason": null,
"public_notes": "Revisar també el soroll a la suspensió.",
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 5501,
"description": "Canvi d'oli i filtre",
"extended_detail": null,
"reference": null,
"line_type": "labor",
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"price_estimated": false,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
]
}
POST /api/v1/budgets/{id}/accept budgets:accept
Acceptar en nom del client
Per quan el client accepta per una altra via (telèfon, en persona, la teva web…). L'evidència és obligatòria: accepted_by i channel (phone, in_person, email, whatsapp, other); note és opcional. Passa per la mateixa regla d'acceptació del programa: estat Aprobado, transició, dades fiscals mínimes del client (si falten, 422 fiscal_data_incomplete amb missing), descompte de campanya, avís intern al taller, confirmació al client segons els avisos configurats i webhooks lead.accepted i budget.accepted. Només des d'«Enviado» (si ja està acceptat respon 200 amb already=true); Cancelado, Rechazado, Desistido, Finalizado o Facturado responen 409 budget_locked. Si el taller exigeix signatura, l'API accepta igualment i ho deixa escrit: «sense signatura, acceptat per integració» (signature=waived_by_integration). A l'historial queda «Acceptat per API en nom del client · integració <clau> · <accepted_by> per <canal>».
Permís necessari: budgets:accept.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del pressupost. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"accepted_by": "Laura Gómez",
"channel": "phone",
"note": "Confirmat per telèfon a les 10:12"
}
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/budgets/1234/accept" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"accepted_by":"Laura Gómez","channel":"phone","note":"Confirmat per telèfon a les 10:12"}'
Resposta
{
"budget": {
"id": 1234,
"status": "Aprobado",
"created_at": "2026-10-06T09:30:00.000Z",
"updated_at": "2026-10-06T09:30:00.000Z",
"channel": "web",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"subcategory": {
"id": 5,
"name": "Mantenimiento"
},
"assigned_user": {
"id": 3,
"name": "Marta"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"appointment": {
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"status": "confirmed",
"client_confirmed_at": null,
"estimated_duration_minutes": 60,
"box": null
},
"date_in": null,
"date_out": null,
"km": 84500,
"client_reference": null,
"waiting_parts": false,
"on_hold": false,
"hold_until": null,
"client_signed_at": null,
"estimated_ready_at": null,
"delivered_at": null,
"reject_reason": null,
"public_notes": "Revisar també el soroll a la suspensió.",
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 5501,
"description": "Canvi d'oli i filtre",
"extended_detail": null,
"reference": null,
"line_type": "labor",
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"price_estimated": false,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
]
},
"already": false,
"signature": "not_required"
}
POST /api/v1/budgets/{id}/reject budgets:accept
Rebutjar en nom del client
Amb motiu obligatori. Mateixa regla que el rebuig del client: des de Pendiente, En cotización, Enviado o Aprobado (si el vehicle encara no ha entrat). Emet lead.rejected i budget.rejected i queda a l'historial amb el nom de la clau.
Permís necessari: budgets:accept.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del pressupost. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"reason": "Ho farà en un altre taller",
"rejected_by": "Laura Gómez",
"channel": "phone"
}
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/budgets/1234/reject" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"reason":"Ho farà en un altre taller","rejected_by":"Laura Gómez","channel":"phone"}'
Resposta
{
"budget": {
"id": 1234,
"status": "Aprobado",
"created_at": "2026-10-06T09:30:00.000Z",
"updated_at": "2026-10-06T09:30:00.000Z",
"channel": "web",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"subcategory": {
"id": 5,
"name": "Mantenimiento"
},
"assigned_user": {
"id": 3,
"name": "Marta"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"appointment": {
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"status": "confirmed",
"client_confirmed_at": null,
"estimated_duration_minutes": 60,
"box": null
},
"date_in": null,
"date_out": null,
"km": 84500,
"client_reference": null,
"waiting_parts": false,
"on_hold": false,
"hold_until": null,
"client_signed_at": null,
"estimated_ready_at": null,
"delivered_at": null,
"reject_reason": null,
"public_notes": "Revisar també el soroll a la suspensió.",
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 5501,
"description": "Canvi d'oli i filtre",
"extended_detail": null,
"reference": null,
"line_type": "labor",
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"price_estimated": false,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
]
},
"already": false,
"signature": "not_required"
}
POST /api/v1/budgets/{id}/documents budgets:write
Adjuntar un document
multipart/form-data amb el camp «file» (JPEG, PNG, WebP o PDF, comprovat pel contingut; màxim 4 MB). Per defecte només el veu el taller; client_visible=true el mostra a l'enllaç de seguiment i mechanic_visible=true a l'app del mecànic. L'empremta d'idempotència inclou el fitxer.
Permís necessari: budgets:write.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del pressupost. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos (multipart/form-data)
| Nom | Tipus | Obligatori | Descripció |
|---|
file | string (binary) | Sí | Fichero |
client_visible | string [true, false] | No | |
mechanic_visible | string [true, false] | No | |
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/budgets/1234/documents" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-F "file=@fichero.pdf" \
-F "client_visible=false" \
-F "mechanic_visible=false"
Resposta
{
"id": 991,
"budget_id": 1234,
"filename": "parte-de-trabajo.pdf",
"content_type": "application/pdf",
"size": 182044,
"url": "https://…/leads/1234/api-parte-de-trabajo.pdf",
"client_visible": false,
"mechanic_visible": false,
"created_at": "2026-10-06T09:30:00.000Z"
}
Factures
POST /api/v1/budgets/{id}/invoice invoices:write
Facturar un pressupost
Fa servir la mateixa facturació del programa: copia les partides i l'impost del pressupost, crea l'assentament comptable i, amb issue=true (per defecte), emet la factura amb la sèrie que toqui, número correlatiu, hash encadenat i QR Verifactu. El pressupost passa a Facturado. Es factura un d'Aprobado, En curso, En espera o Finalizado amb import; si ja té factura es retorna aquesta (created=false), mai una segona. Emet invoice.created i invoice.issued. Les factures rectificatives no estan disponibles per API: es fan des del programa.
Permís necessari: invoices:write.
Clau de client: no disponible (403 client_key_forbidden).
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id del pressupost. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"issue": true,
"pay_method": "TARJETA"
}
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/budgets/1234/invoice" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"issue":true,"pay_method":"TARJETA"}'
Resposta
{
"invoice": {
"id": 412,
"number": 87,
"series": "F26",
"full_number": "F2687",
"kind": "invoice",
"rectifies_number": null,
"status": "issued",
"date": "2026-10-06",
"issued_at": "2026-10-06T09:30:00.000Z",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"budget_id": 1234,
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"plate": "1234 KLM",
"km": 84500,
"total": 78.65,
"currency": "EUR",
"payments": {
"paid": 78.65,
"pending": 0,
"settled": true
},
"payment_method": "Tarjeta",
"rebu": false,
"verifactu_hash": "3f9a…",
"registered_externally": false,
"billing": {
"name": "Laura Gómez",
"tax_id": "12345678Z",
"address": "C/ Mayor 12",
"city": "Barcelona",
"zip": "08001",
"province": "Barcelona"
},
"date_in": null,
"date_out": null,
"public_notes": null,
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 9001,
"description": "Canvi d'oli i filtre",
"reference": null,
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
],
"payment_list": [
{
"id": 77,
"date": "2026-10-06T09:30:00.000Z",
"amount": 78.65,
"currency": "EUR",
"method": "Tarjeta"
}
]
},
"created": true
}
GET /api/v1/invoices invoices:read
Llistar factures
Factures emeses i esborranys, ordenades per id. Inclou el resum de cobraments.
Permís necessari: invoices:read.
Clau de client: només retorna o crea dades del seu client.
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
from | string (date-time) | No | Data de factura des de. |
to | string (date-time) | No | Data de factura fins a. |
client_id | integer | No | Filtrar per client. |
status | string [draft, issued, cancelled] | No | Estat de la factura. |
series | string | No | Sèrie exacta. |
limit | integer · default 50 | No | Resultats per pàgina (1–200). |
cursor | string | No | Cursor opac retornat a next_cursor de la pàgina anterior. |
Exemple
curl "https://el-teu-taller.example/api/v1/invoices" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"data": [
{
"id": 412,
"number": 87,
"series": "F26",
"full_number": "F2687",
"kind": "invoice",
"rectifies_number": null,
"status": "issued",
"date": "2026-10-06",
"issued_at": "2026-10-06T09:30:00.000Z",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"budget_id": 1234,
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"plate": "1234 KLM",
"km": 84500,
"total": 78.65,
"currency": "EUR",
"payments": {
"paid": 78.65,
"pending": 0,
"settled": true
},
"payment_method": "Tarjeta",
"rebu": false,
"verifactu_hash": "3f9a…",
"registered_externally": false
}
],
"next_cursor": "aWQ6MTIzNA",
"has_more": true
}
GET /api/v1/invoices/{id} invoices:read
Detall d'una factura
Permís necessari: invoices:read.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id de la factura. |
Exemple
curl "https://el-teu-taller.example/api/v1/invoices/1234" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"id": 412,
"number": 87,
"series": "F26",
"full_number": "F2687",
"kind": "invoice",
"rectifies_number": null,
"status": "issued",
"date": "2026-10-06",
"issued_at": "2026-10-06T09:30:00.000Z",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"budget_id": 1234,
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"plate": "1234 KLM",
"km": 84500,
"total": 78.65,
"currency": "EUR",
"payments": {
"paid": 78.65,
"pending": 0,
"settled": true
},
"payment_method": "Tarjeta",
"rebu": false,
"verifactu_hash": "3f9a…",
"registered_externally": false,
"billing": {
"name": "Laura Gómez",
"tax_id": "12345678Z",
"address": "C/ Mayor 12",
"city": "Barcelona",
"zip": "08001",
"province": "Barcelona"
},
"date_in": null,
"date_out": null,
"public_notes": null,
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 9001,
"description": "Canvi d'oli i filtre",
"reference": null,
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
],
"payment_list": [
{
"id": 77,
"date": "2026-10-06T09:30:00.000Z",
"amount": 78.65,
"currency": "EUR",
"method": "Tarjeta"
}
]
}
GET /api/v1/invoices/{id}/pdf invoices:read
PDF d'una factura
El mateix PDF que genera el programa (amb QR Verifactu si la factura està emesa). Resposta application/pdf.
Permís necessari: invoices:read.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id de la factura. |
Exemple
curl "https://el-teu-taller.example/api/v1/invoices/1234/pdf" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
(application/pdf)
POST /api/v1/invoices/{id}/payments invoices:write
Anotar un cobrament
Mateix registre de cobraments que la fitxa de la factura: la marca «pagada» es recalcula amb tots els cobraments (mai es força) i s'emet payment.received. Només sobre factures emeses. Retorna la factura amb el seu resum de cobraments.
Permís necessari: invoices:write.
Clau de client: no disponible (403 client_key_forbidden).
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | integer | Sí | Id de la factura. |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"amount": 245.3,
"date": "2026-10-13",
"pay_method": "TARJETA",
"notes": "Cobrat al taulell"
}
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/invoices/1234/payments" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"amount":245.3,"date":"2026-10-13","pay_method":"TARJETA","notes":"Cobrat al taulell"}'
Resposta
{
"id": 412,
"number": 87,
"series": "F26",
"full_number": "F2687",
"kind": "invoice",
"rectifies_number": null,
"status": "issued",
"date": "2026-10-06",
"issued_at": "2026-10-06T09:30:00.000Z",
"client_id": 1204,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"budget_id": 1234,
"vehicle_id": 871,
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"plate": "1234 KLM",
"km": 84500,
"total": 78.65,
"currency": "EUR",
"payments": {
"paid": 78.65,
"pending": 0,
"settled": true
},
"payment_method": "Tarjeta",
"rebu": false,
"verifactu_hash": "3f9a…",
"registered_externally": false,
"billing": {
"name": "Laura Gómez",
"tax_id": "12345678Z",
"address": "C/ Mayor 12",
"city": "Barcelona",
"zip": "08001",
"province": "Barcelona"
},
"date_in": null,
"date_out": null,
"public_notes": null,
"totals": {
"base": 65,
"tax": 13.65,
"total": 78.65,
"currency": "EUR",
"tax_rates": [
{
"rate": 21,
"base": 65,
"quota": 13.65
}
]
},
"lines": [
{
"id": 9001,
"description": "Canvi d'oli i filtre",
"reference": null,
"group_title": null,
"quantity": 1,
"unit_price": 65,
"discount_pct": 0,
"tax_rate": 21,
"tax_exempt_code": null,
"base": 65,
"currency": "EUR",
"sort_order": 0
}
],
"payment_list": [
{
"id": 77,
"date": "2026-10-06T09:30:00.000Z",
"amount": 78.65,
"currency": "EUR",
"method": "Tarjeta"
}
]
}
Cites
GET /api/v1/appointments appointments:read
Cites confirmades i proposades
Per defecte els propers 30 dies. status=confirmed són cites fixades a l'agenda; status=proposed són propostes del client pendents que el taller confirmi (bloquegen el forat).
Permís necessari: appointments:read.
Clau de client: només retorna o crea dades del seu client.
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
from | string (date-time) | No | Inici del rang (per defecte ara). |
to | string (date-time) | No | Fi del rang (per defecte +30 dies, màxim 1 any). |
status | string [confirmed, proposed] | No | Només un tipus. |
box_id | integer | No | Filtrar per elevador/box. |
Exemple
curl "https://el-teu-taller.example/api/v1/appointments" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"data": [
{
"id": "b1234",
"budget_id": 1234,
"status": "confirmed",
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"estimated_duration_minutes": 60,
"client_confirmed_at": null,
"budget_status": "Aprobado",
"checked_in_at": null,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"box": {
"id": 2,
"name": "Elevador 2"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"channel": null,
"proposed_at": null
}
],
"from": "2026-10-06T00:00:00.000Z",
"to": "2026-11-05T00:00:00.000Z"
}
POST /api/v1/appointments appointments:write
Proposar o reservar una cita
Segueix el mode de reserva del taller (booking_mode a GET /workshop). En «propose» es crea una proposta (status=proposed) que bloqueja el forat fins que el taller la confirma; demanar mode=book respon 403 booking_mode_propose_only. En «book» la cita queda ferma (status=confirmed), tret que demanis mode=propose. El forat es valida amb la mateixa lògica que /appointments/availability; si no és lliure, 409 slot_unavailable amb fins a 3 alternatives a error.alternatives. No s'avisa el client tret de notify_client=true amb communications:send.
Permís necessari: appointments:write.
Clau de client: només retorna o crea dades del seu client.
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | Sí | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"budget_id": 1234,
"start": "2026-10-14T09:00:00+02:00",
"box_id": 2,
"duration_minutes": 60,
"mode": "propose",
"notify_client": false
}
Exemple
curl -X POST "https://el-teu-taller.example/api/v1/appointments" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"budget_id":1234,"start":"2026-10-14T09:00:00+02:00","box_id":2,"duration_minutes":60,"mode":"propose","notify_client":false}'
Resposta
{
"id": "b1234",
"budget_id": 1234,
"status": "confirmed",
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"estimated_duration_minutes": 60,
"client_confirmed_at": null,
"budget_status": "Aprobado",
"checked_in_at": null,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"box": {
"id": 2,
"name": "Elevador 2"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"channel": null,
"proposed_at": null
}
GET /api/v1/appointments/availability appointments:read
Forats lliures
Mateixa lògica que l'agenda i la web de seguiment: horari del taller i de cada box, dinar, festius nacionals, autonòmics i locals, cites obertes i propostes pendents (que bloquegen el seu forat). Inicis cada 30 min i com a mínim 1 h des d'ara. Per defecte els propers 7 dies (màxim 31). Inclou el booking_mode del taller.
Permís necessari: appointments:read.
Clau de client: permès (no porta dades d'altres clients).
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
from | string (date-time) | No | Des de (per defecte ara). |
to | string (date-time) | No | Fins a (per defecte +7 dies; màxim 31 dies). |
duration_minutes | integer | No | Durada de la cita (15–720). Per defecte la mínima de l'agenda. |
box_id | integer | No | Només aquest box. |
limit | integer · default 100 | No | Màxim de forats (1–500). |
Exemple
curl "https://el-teu-taller.example/api/v1/appointments/availability" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"data": [
{
"start": "2026-10-14T07:00:00.000Z",
"end": "2026-10-14T08:00:00.000Z",
"box": {
"id": 2,
"name": "Elevador 2"
}
}
],
"duration_minutes": 60,
"from": "2026-10-14T00:00:00.000Z",
"to": "2026-10-21T00:00:00.000Z",
"booking_mode": "propose"
}
DELETE /api/v1/appointments/{id} appointments:write
Anul·lar una cita o retirar una proposta
b<pressupost>: anul·la la cita confirmada (igual que «Cancel·lar cita» a la fitxa). p<proposta>: retira la proposta pendent; amb notify_client=true i communications:send es convida el client a triar una altra hora. Emet appointment.cancelled.
Permís necessari: appointments:write.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | string | Sí | Id de la cita (b1234 o p88). |
Consulta (query)
| Nom | Tipus | Obligatori | Descripció |
|---|
notify_client | boolean · default false | No | Només propostes: avisar el client. |
Exemple
curl -X DELETE "https://el-teu-taller.example/api/v1/appointments/b1234" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"ok": true,
"id": "b1234",
"status": "cancelled"
}
GET /api/v1/appointments/{id} appointments:read
Detall d'una cita
Permís necessari: appointments:read.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | string | Sí | Id de la cita (b1234 o p88). |
Exemple
curl "https://el-teu-taller.example/api/v1/appointments/b1234" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Resposta
{
"id": "b1234",
"budget_id": 1234,
"status": "confirmed",
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"estimated_duration_minutes": 60,
"client_confirmed_at": null,
"budget_status": "Aprobado",
"checked_in_at": null,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"box": {
"id": 2,
"name": "Elevador 2"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"channel": null,
"proposed_at": null
}
PATCH /api/v1/appointments/{id} appointments:write
Moure una cita o canviar una proposta
b<pressupost>: mou la cita en ferm a la nova hora (només si el taller treballa en mode «reservar»; en mode «proposar» respon 403 booking_mode_propose_only: crea una proposta amb POST /appointments). p<proposta>: retira la proposta i en crea una altra a la nova hora (canvia l'id). El forat es valida igual que en crear (409 slot_unavailable amb alternatives). Emet appointment.updated.
Permís necessari: appointments:write.
Clau de client: només si el recurs és del seu client; si no, 404.
Paràmetres
| Nom | Tipus | Obligatori | Descripció |
|---|
id | string | Sí | Id de la cita (b1234 o p88). |
Capçaleres
| Nom | Tipus | Obligatori | Descripció |
|---|
Idempotency-Key | string | No | Clau única per operació (es recomana un UUID). Repetir-la amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos, 409 idempotency_conflict. |
Cos
{
"start": "2026-10-15T10:00:00+02:00",
"box_id": 2,
"duration_minutes": 60,
"notify_client": false
}
Exemple
curl -X PATCH "https://el-teu-taller.example/api/v1/appointments/b1234" \
-H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"start":"2026-10-15T10:00:00+02:00","box_id":2,"duration_minutes":60,"notify_client":false}'
Resposta
{
"id": "b1234",
"budget_id": 1234,
"status": "confirmed",
"start": "2026-10-06T09:30:00.000Z",
"end": "2026-10-06T10:30:00.000Z",
"estimated_duration_minutes": 60,
"client_confirmed_at": null,
"budget_status": "Aprobado",
"checked_in_at": null,
"client": {
"id": 1204,
"name": "Laura Gómez"
},
"vehicle": {
"id": 871,
"plate": "1234 KLM",
"brand": "Seat",
"model": "León"
},
"mechanic": {
"id": 3,
"name": "Marta"
},
"box": {
"id": 2,
"name": "Elevador 2"
},
"category": {
"id": 5,
"name": "Mantenimiento"
},
"channel": null,
"proposed_at": null
}