P Programa Taller
ESCAT
▶ Demo 3 mesos per 1 €
API REST v1

Referència de l'API

Tots els endpoints de la versió 1 amb els paràmetres, exemples de petició i resposta, permisos, errors i esdeveniments de webhook.

URL baseCada taller té l'API al seu domini: https://<el-seu-domini>/api/v1. L'URL del teu taller apareix a «Desarrolladores / API»; als exemples fem servir https://el-teu-taller.example.

Autenticació

Envia la clau a la capçalera Authorization: Bearer pt_live_… (o X-Api-Key). Les claus pt_test_… poden llegir, però qualsevol operació amb efectes respon 403 test_key_forbidden.

Convencions

Dates en ISO 8601 UTC; imports en euros amb dos decimals i currency: "EUR"; identificadors enters; noms de camp estables en snake_case. El personal del taller apareix només com a { id, name }.

Paginació

Els llistats retornen { data, next_cursor, has_more }. Demana la pàgina següent repetint la crida amb ?cursor=<next_cursor>. limit va d'1 a 200 (50 per defecte).

Format d'error

{
  "error": {
    "code": "insufficient_scope",
    "message": "La clau API no té el permís «budgets:read»."
  }
}
HTTPCodiMissatge
401missing_api_keyFalta la clau API: envia-la a la capçalera Authorization: Bearer pt_… o X-Api-Key.
401invalid_api_keyLa clau API no és vàlida per a aquesta instància.
401revoked_api_keyLa clau API està revocada.
401expired_api_keyLa clau API ha caducat.
403ip_not_allowedL'adreça IP d'origen no és a la llista permesa d'aquesta clau.
403insufficient_scopeLa clau API no té el permís necessari per a aquesta operació.
403test_key_forbiddenUna clau de prova (pt_test_) no pot fer operacions amb efectes: fes servir una clau live.
429rate_limitedHas superat el límit de peticions d'aquesta clau. Espera i torna-ho a provar.
503instance_rate_limitedLa instància està rebent massa peticions per API en aquest moment. Torna-ho a provar d'aquí a uns segons.
429plan_quota_exceededS'ha esgotat la quota diària de peticions del pla d'API del taller. Es renova a les 00:00 UTC; per a més volum, millora el pla.
403plan_scope_not_allowedEl pla d'API del taller no inclou aquest permís. Per fer-lo servir cal millorar el pla.
400bad_requestLa petició no és vàlida.
404not_foundNo s'ha trobat el recurs.
502upstream_errorUn servei extern ha rebutjat l'operació.
500internal_errorError intern.
422validation_errorEl cos de la petició no és vàlid: revisa la llista «fields».
400idempotency_key_requiredFalta la capçalera Idempotency-Key (obligatòria a tot POST; de 8 a 255 caràcters visibles).
409idempotency_conflictAquesta Idempotency-Key ja s'ha fet servir les últimes 24 h amb una altra petició.
409idempotency_in_progressHi ha una altra petició amb la mateixa Idempotency-Key en curs. Torna-ho a provar d'aquí a uns segons.
409client_existsJa existeix un client amb aquest telèfon, email o NIF/CIF.
409client_erasedEl client va demanar l'esborrat de les seves dades (RGPD): la fitxa no admet canvis ni altes associades.
409vehicle_existsAquest client ja té un vehicle amb aquesta matrícula.
409vehicle_belongs_to_other_clientAquesta matrícula ja està donada d'alta a nom d'un altre client.
409budget_lockedEl pressupost està tancat i ja no admet aquest canvi.
409invalid_status_transitionEl pressupost no pot passar a aquest estat des de l'estat actual.
403status_transition_forbiddenAquest canvi d'estat no està disponible per API.
403client_acceptance_requiredL'acceptació del pressupost l'ha de fer el client des del seu enllaç de seguiment signat.
403booking_mode_propose_onlyEl taller treballa en mode «proposar cita»: només es poden crear propostes que el taller confirma.
409slot_unavailableAquest forat no està disponible.
413payload_too_largeEl fitxer supera la mida màxima (4 MB).
415unsupported_media_typeTipus de fitxer no admès: només JPEG, PNG, WebP o PDF.

Escriptures i idempotència

Tot POST exigeix la capçalera Idempotency-Key (un UUID nou per operació). Repetir la mateixa clau amb el mateix cos en 24 h retorna la resposta desada amb Idempotent-Replay: true; amb un altre cos respon 409 idempotency_conflict. Els cossos es validen contra el seu esquema i qualsevol camp desconegut es rebutja: 422 validation_error amb la llista fields (path i message).

Guies

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 i tracking_url: comparteix-la amb el client perquè accepti i signi.

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.

Permisos (scopes)

PermísNomAmb efectesDescripció
clients:readLlegir clientsNoConsultar fitxes de clients i les seves dades de contacte.
clients:writeCrear i editar clientsSíDonar d'alta clients nous i modificar els existents.
vehicles:readLlegir vehiclesNoConsultar vehicles, matrícules i el seu historial.
vehicles:writeCrear i editar vehiclesSíDonar d'alta vehicles i modificar-ne les dades.
budgets:readLlegir pressupostosNoConsultar pressupostos, les seves partides i el seu estat.
budgets:writeCrear i editar pressupostosSíCrear pressupostos, afegir partides i canviar-ne l'estat.
invoices:readLlegir facturesNoConsultar factures emeses, imports i cobraments. Emetre factures no està disponible per API.
appointments:readLlegir citesNoConsultar l'agenda de cites i els forats disponibles.
appointments:writeReservar i cancel·lar citesSíCrear, moure i cancel·lar cites a l'agenda.
communications:readLlegir comunicacionsNoConsultar el registre d'emails, SMS, WhatsApp i trucades (inclou el contingut complet).
communications:sendEnviar email i SMSSíEnviar emails i SMS transaccionals des de la instància; consumeix saldo.
catalog:readLlegir catàlegNoConsultar serveis, tarifes i conceptes del tarifari.
stock:readLlegir estocNoConsultar existències i referències de recanvis.
stock:writeAjustar estocSíDonar entrades i sortides de recanvis.
webhooks:manageGestionar webhooksSíCrear, llistar i esborrar les subscripcions a esdeveniments d'aquesta clau.
reports:readLlegir informesNoConsultar xifres agregades de facturació, activitat i rendiment.

General

GET /api/v1/ping Qualsevol clau

Provar la connexió

Retorna el nom de la clau, l'entorn, els permisos i l'estat dels límits. Serveix qualsevol clau vàlida.

Qualsevol clau vàlida, sense cap permís concret.

Exemple

curl "https://el-teu-taller.example/api/v1/ping" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Resposta

{
  "ok": true,
  "key": {
    "id": 7,
    "name": "CRM",
    "environment": "live",
    "scopes": [
      "clients:read"
    ],
    "expires_at": null
  },
  "rate_limit": {
    "per_minute": {
      "limit": 60,
      "used": 1,
      "remaining": 59
    },
    "per_day": {
      "limit": 20000,
      "used": 1,
      "remaining": 19999
    }
  },
  "instance": "taller.ejemplo.com",
  "server_time": "2026-10-06T09:30:00.000Z",
  "version": "v1"
}

GET /api/v1/workshop Qualsevol clau

Dades públiques del taller

Nom, raó social, CIF, adreça, contacte, horari setmanal de l'agenda, mode de reserva de cites, festius propers i zona horària.

Qualsevol clau vàlida, sense cap permís concret.

Exemple

curl "https://el-teu-taller.example/api/v1/workshop" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Resposta

{
  "name": "Taller Ejemplo",
  "legal_name": "Taller Ejemplo S.L.",
  "tax_id": "B12345678",
  "address": "C/ Industria 4",
  "city": "Barcelona",
  "zip": "08020",
  "province": "Barcelona",
  "phone": "+34931234567",
  "whatsapp": "+34600111222",
  "email": "taller@ejemplo.com",
  "web": "https://www.ejemplo.com",
  "logo_url": null,
  "timezone": "Europe/Madrid",
  "currency": "EUR",
  "booking_mode": "propose",
  "schedule": {
    "mon": {
      "start": "08:00",
      "end": "19:00",
      "closed": false
    },
    "tue": {
      "start": "08:00",
      "end": "19:00",
      "closed": false
    },
    "wed": {
      "start": "08:00",
      "end": "19:00",
      "closed": false
    },
    "thu": {
      "start": "08:00",
      "end": "19:00",
      "closed": false
    },
    "fri": {
      "start": "08:00",
      "end": "19:00",
      "closed": false
    },
    "sat": {
      "start": "08:00",
      "end": "19:00",
      "closed": false
    },
    "sun": {
      "start": "08:00",
      "end": "19:00",
      "closed": false
    }
  },
  "lunch_break": {
    "start": "13:30",
    "end": "15:00"
  },
  "min_slot_minutes": 60,
  "upcoming_holidays": [
    {
      "date": "2026-10-12",
      "name": "Fiesta Nacional de España",
      "scope": "nacional"
    }
  ]
}

GET /api/v1/openapi.json Sense autenticació

Especificació OpenAPI 3.1

Fitxer generat des d'aquest mateix catàleg. Sense autenticació. Admet ?lang=es|en|ca|pt|fr|bg per als textos.

Sense autenticació.

Consulta (query)

NomTipusObligatoriDescripció
langstring [es, en, ca, pt, fr, bg] · default esNoIdioma de les descripcions.

Exemple

curl "https://el-teu-taller.example/api/v1/openapi.json"

Resposta

{}

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.

Consulta (query)

NomTipusObligatoriDescripció
searchstringNoCerca al nom, telèfon, email i NIF/CIF (mínim 2 caràcters).
expandstring [vehicles]NoRelacions opcionals que cal incloure.
limitinteger · default 50NoResultats per pàgina (1–200).
cursorstringNoCursor 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.

Consulta (query)

NomTipusObligatoriDescripció
on_conflictstring [error, return_existing] · default errorNoerror (per defecte): 409 si ja existeix. return_existing: 200 amb el client existent.

Capçaleres

NomTipusObligatoriDescripció
Idempotency-KeystringSí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.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del client.

Consulta (query)

NomTipusObligatoriDescripció
expandstring [vehicles]NoRelacions 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.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del client.

Capçaleres

NomTipusObligatoriDescripció
Idempotency-KeystringNoClau ú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.

Consulta (query)

NomTipusObligatoriDescripció
platestringNoMatrícula exacta (s'ignoren espais i guions).
client_idintegerNoFiltrar per client.
statusstring [activo, baja_temporal, baja]NoEstat del vehicle.
limitinteger · default 50NoResultats per pàgina (1–200).
cursorstringNoCursor 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.

Consulta (query)

NomTipusObligatoriDescripció
on_conflictstring [error, return_existing] · default errorNoerror (per defecte) o return_existing.

Capçaleres

NomTipusObligatoriDescripció
Idempotency-KeystringSí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.

Paràmetres

NomTipusObligatoriDescripció
idintegerSí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.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del vehicle.

Capçaleres

NomTipusObligatoriDescripció
Idempotency-KeystringNoClau ú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"
}

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.

Consulta (query)

NomTipusObligatoriDescripció
statusstringNoEstat exacte, amb el valor en castellà (Pendiente, Enviado, Aprobado, Finalizado, Facturado, Rechazado…).
client_idintegerNoFiltrar per client.
vehicle_idintegerNoFiltrar per vehicle.
fromstring (date-time)NoCreats a partir d'aquesta data.
tostring (date-time)NoCreats fins a aquesta data.
updated_sincestring (date-time)NoNomés registres modificats a partir d'aquesta data (ISO 8601).
limitinteger · default 50NoResultats per pàgina (1–200).
cursorstringNoCursor 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,
      "delivered_at": null,
      "reject_reason": null,
      "tracking_url": "https://taller.ejemplo.com/public/seguimiento?id=…"
    }
  ],
  "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.

Capçaleres

NomTipusObligatoriDescripció
Idempotency-KeystringSí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,
  "delivered_at": null,
  "reject_reason": null,
  "tracking_url": "https://taller.ejemplo.com/public/seguimiento?id=…",
  "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.

Paràmetres

NomTipusObligatoriDescripció
idintegerSí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,
  "delivered_at": null,
  "reject_reason": null,
  "tracking_url": "https://taller.ejemplo.com/public/seguimiento?id=…",
  "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}/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.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del pressupost.

Capçaleres

NomTipusObligatoriDescripció
Idempotency-KeystringSí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,
    "delivered_at": null,
    "reject_reason": null,
    "tracking_url": "https://taller.ejemplo.com/public/seguimiento?id=…",
    "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.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del pressupost.
lineIdintegerSíId de la partida.

Capçaleres

NomTipusObligatoriDescripció
Idempotency-KeystringNoClau ú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,
    "delivered_at": null,
    "reject_reason": null,
    "tracking_url": "https://taller.ejemplo.com/public/seguimiento?id=…",
    "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.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del pressupost.
lineIdintegerSí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,
  "delivered_at": null,
  "reject_reason": null,
  "tracking_url": "https://taller.ejemplo.com/public/seguimiento?id=…",
  "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 amb la tracking_url: l'acceptació la signa el client. Facturar, rebutjar o desistir responen 403 status_transition_forbidden; 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 no avisa el client excepte Finalizado amb notify_client=true i communications:send.

Permís necessari: budgets:write.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del pressupost.

Capçaleres

NomTipusObligatoriDescripció
Idempotency-KeystringSí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,
  "delivered_at": null,
  "reject_reason": null,
  "tracking_url": "https://taller.ejemplo.com/public/seguimiento?id=…",
  "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}/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.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del pressupost.

Capçaleres

NomTipusObligatoriDescripció
Idempotency-KeystringSí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)

NomTipusObligatoriDescripció
filestring (binary)SíFichero
client_visiblestring [true, false]No
mechanic_visiblestring [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

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.

Consulta (query)

NomTipusObligatoriDescripció
fromstring (date-time)NoData de factura des de.
tostring (date-time)NoData de factura fins a.
client_idintegerNoFiltrar per client.
statusstring [draft, issued, cancelled]NoEstat de la factura.
seriesstringNoSèrie exacta.
limitinteger · default 50NoResultats per pàgina (1–200).
cursorstringNoCursor 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…"
    }
  ],
  "next_cursor": "aWQ6MTIzNA",
  "has_more": true
}

GET /api/v1/invoices/{id} invoices:read

Detall d'una factura

Permís necessari: invoices:read.

Paràmetres

NomTipusObligatoriDescripció
idintegerSí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…",
  "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.

Paràmetres

NomTipusObligatoriDescripció
idintegerSí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)

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.

Consulta (query)

NomTipusObligatoriDescripció
fromstring (date-time)NoInici del rang (per defecte ara).
tostring (date-time)NoFi del rang (per defecte +30 dies, màxim 1 any).
statusstring [confirmed, proposed]NoNomés un tipus.
box_idintegerNoFiltrar 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.

Capçaleres

NomTipusObligatoriDescripció
Idempotency-KeystringSí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.

Consulta (query)

NomTipusObligatoriDescripció
fromstring (date-time)NoDes de (per defecte ara).
tostring (date-time)NoFins a (per defecte +7 dies; màxim 31 dies).
duration_minutesintegerNoDurada de la cita (15–720). Per defecte la mínima de l'agenda.
box_idintegerNoNomés aquest box.
limitinteger · default 100NoMà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.

Paràmetres

NomTipusObligatoriDescripció
idstringSíId de la cita (b1234 o p88).

Consulta (query)

NomTipusObligatoriDescripció
notify_clientboolean · default falseNoNomé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"
}

Catàleg

GET /api/v1/catalog/services catalog:read

Categories i subcategories de servei

Permís necessari: catalog:read.

Exemple

curl "https://el-teu-taller.example/api/v1/catalog/services" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Resposta

{
  "data": [
    {
      "id": 5,
      "name": "Mantenimiento",
      "reference_price": 120,
      "currency": "EUR",
      "subcategories": [
        {
          "id": 51,
          "name": "Canvi d'oli",
          "reference_price": 65,
          "currency": "EUR"
        }
      ]
    }
  ]
}

GET /api/v1/catalog/rates catalog:read

Tarifes de mà d'obra

Només el preu de venda per hora; el cost mai no surt per l'API.

Permís necessari: catalog:read.

Exemple

curl "https://el-teu-taller.example/api/v1/catalog/rates" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Resposta

{
  "data": [
    {
      "id": 1,
      "name": "Mà d'obra general",
      "price_per_hour": 48,
      "currency": "EUR",
      "is_default": true
    }
  ]
}

Comunicacions

GET /api/v1/communications communications:read

Registre de comunicacions

Últimes comunicacions (email, SMS, WhatsApp, trucades, push) amb el contingut complet, de la més recent a la més antiga.

Permís necessari: communications:read.

Consulta (query)

NomTipusObligatoriDescripció
channelstring [all, email, sms, whatsapp, call, push] · default allNoCanal.
limitinteger · default 50NoMàxim de resultats (1–200).

Exemple

curl "https://el-teu-taller.example/api/v1/communications" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Resposta

{
  "data": [
    {
      "id": "c_8812",
      "channel": "email",
      "direction": "out",
      "recipient": "laura@ejemplo.com",
      "subject": "El seu pressupost",
      "body": "Hola Laura, …",
      "idlead": 1234,
      "idclient": 1204,
      "clientName": "Laura Gómez",
      "status": "sent",
      "created_at": "2026-10-06T09:30:00.000Z",
      "duration": null,
      "recordingUrl": null,
      "agent": null,
      "fromNumber": null,
      "toNumber": null
    }
  ],
  "next_cursor": null,
  "has_more": false
}

GET /api/v1/logs communications:read

Registre de comunicacions (àlies antic)

Mateixa consulta que /communications però retorna { items }. Es manté per compatibilitat; fes servir /communications.

Permís necessari: communications:read.

Consulta (query)

NomTipusObligatoriDescripció
channelstring [all, email, sms, whatsapp, call, push] · default allNoCanal.
limitinteger · default 50NoMàxim de resultats (1–200).

Exemple

curl "https://el-teu-taller.example/api/v1/logs" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Resposta

{
  "items": [
    {
      "id": "c_8812",
      "channel": "email",
      "direction": "out",
      "recipient": "laura@ejemplo.com",
      "subject": "El seu pressupost",
      "body": "Hola Laura, …",
      "idlead": 1234,
      "idclient": 1204,
      "clientName": "Laura Gómez",
      "status": "sent",
      "created_at": "2026-10-06T09:30:00.000Z",
      "duration": null,
      "recordingUrl": null,
      "agent": null,
      "fromNumber": null,
      "toNumber": null
    }
  ]
}

POST /api/v1/email communications:send

Enviar un email transaccional

Surt amb el compte de correu configurat al taller i queda al registre de Comunicació. Si rebota, l'email del client es marca com a no vàlid.

Permís necessari: communications:send.

Cos

{
  "to": "cliente@ejemplo.com",
  "subject": "El seu vehicle és a punt",
  "text": "Ja el pot passar a recollir.",
  "html": "<p>Ja el pot passar a recollir.</p>",
  "fromName": "Taller",
  "replyTo": "taller@ejemplo.com"
}

Exemple

curl -X POST "https://el-teu-taller.example/api/v1/email" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"to":"cliente@ejemplo.com","subject":"El seu vehicle és a punt","text":"Ja el pot passar a recollir.","html":"<p>Ja el pot passar a recollir.</p>","fromName":"Taller","replyTo":"taller@ejemplo.com"}'

Resposta

{
  "ok": true
}

POST /api/v1/sms communications:send

Enviar un SMS transaccional

Surt amb el servei d'SMS configurat al taller i queda al registre de Comunicació, on s'actualitza l'estat de lliurament.

Permís necessari: communications:send.

Cos

{
  "to": "+34600111222",
  "body": "El seu vehicle ja es pot recollir."
}

Exemple

curl -X POST "https://el-teu-taller.example/api/v1/sms" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"to":"+34600111222","body":"El seu vehicle ja es pot recollir."}'

Resposta

{
  "ok": true
}

Webhooks

GET /api/v1/webhooks webhooks:manage

Llistar els webhooks de la clau

Inclou el catàleg d'esdeveniments disponibles. Mai no retorna els secrets.

Permís necessari: webhooks:manage.

Exemple

curl "https://el-teu-taller.example/api/v1/webhooks" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Resposta

{
  "items": [
    {
      "id": 3,
      "url": "https://tu-sistema.com/webhooks/taller",
      "events": [
        "lead.accepted"
      ],
      "description": "CRM",
      "active": true,
      "created_at": "2026-10-06T09:30:00.000Z"
    }
  ],
  "events": [
    {
      "event": "lead.accepted",
      "label": "Pressupost acceptat",
      "description": "texto"
    }
  ]
}

POST /api/v1/webhooks webhooks:manage

Crear un webhook

El secret de signatura (whsec_…) només viatja en aquesta resposta.

Permís necessari: webhooks:manage.

Cos

{
  "url": "https://tu-sistema.com/webhooks/taller",
  "events": [
    "lead.accepted"
  ],
  "description": "CRM"
}

Exemple

curl -X POST "https://el-teu-taller.example/api/v1/webhooks" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://tu-sistema.com/webhooks/taller","events":["lead.accepted"],"description":"CRM"}'

Resposta

{
  "item": {
    "id": 3,
    "url": "https://tu-sistema.com/webhooks/taller",
    "events": [
      "lead.accepted"
    ],
    "description": "CRM",
    "active": true,
    "created_at": "2026-10-06T09:30:00.000Z"
  },
  "secret": "whsec_…"
}

GET /api/v1/webhooks/{id} webhooks:manage

Detall d'un webhook i les darreres entregues

Permís necessari: webhooks:manage.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del webhook.

Exemple

curl "https://el-teu-taller.example/api/v1/webhooks/1234" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Resposta

{
  "item": {
    "id": 3,
    "url": "https://tu-sistema.com/webhooks/taller",
    "events": [
      "lead.accepted"
    ],
    "description": "CRM",
    "active": true,
    "created_at": "2026-10-06T09:30:00.000Z"
  },
  "deliveries": [
    {}
  ]
}

PATCH /api/v1/webhooks/{id} webhooks:manage

Modificar un webhook

Permís necessari: webhooks:manage.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del webhook.

Cos

{
  "url": "texto",
  "events": [
    "texto"
  ],
  "description": "texto",
  "active": false
}

Exemple

curl -X PATCH "https://el-teu-taller.example/api/v1/webhooks/1234" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"url":"texto","events":["texto"],"description":"texto","active":false}'

Resposta

{
  "item": {
    "id": 3,
    "url": "https://tu-sistema.com/webhooks/taller",
    "events": [
      "lead.accepted"
    ],
    "description": "CRM",
    "active": true,
    "created_at": "2026-10-06T09:30:00.000Z"
  }
}

DELETE /api/v1/webhooks/{id} webhooks:manage

Esborrar un webhook

Permís necessari: webhooks:manage.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del webhook.

Exemple

curl -X DELETE "https://el-teu-taller.example/api/v1/webhooks/1234" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Resposta

{
  "ok": true
}

POST /api/v1/webhooks/{id}/test webhooks:manage

Enviar una entrega de prova (test.ping) al webhook

Permís necessari: webhooks:manage.

Paràmetres

NomTipusObligatoriDescripció
idintegerSíId del webhook.

Exemple

curl -X POST "https://el-teu-taller.example/api/v1/webhooks/1234/test" \
  -H "Authorization: Bearer pt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Resposta

{
  "ok": true,
  "status": 200
}

Webhooks

Càrrega

{
  "event": "lead.accepted",
  "timestamp": "2026-10-06T10:15:00.000Z",
  "data": {
    "leadId": 1234,
    "from": "Enviado",
    "to": "Aprobado"
  }
}
EsdevenimentDescripció
lead.createdPressupost creat
S'ha creat un pressupost nou (des del programa, la web, l'email o l'assistent).
lead.sentPressupost enviat
El pressupost s'ha enviat al client.
lead.acceptedPressupost acceptat
El client o el taller han aprovat el pressupost.
lead.rejectedPressupost rebutjat
El pressupost s'ha rebutjat, amb el motiu si n'hi ha.
lead.status_changedCanvi d'estat
Qualsevol canvi d'estat del pressupost (inclou els anteriors).
appointment.proposedCita proposada
Un client proposa una cita pendent que el taller la confirmi.
appointment.confirmedCita confirmada
Una cita queda confirmada a l'agenda.
appointment.cancelledCita cancel·lada
S'ha anul·lat la cita d'un pressupost.
vehicle.checked_inVehicle rebut
El vehicle ha entrat al taller (recepció o sense cita).
vehicle.readyVehicle a punt
La reparació ha acabat i el vehicle es pot recollir.
vehicle.deliveredVehicle lliurat
El client ha recollit el vehicle.
invoice.issuedFactura emesa
S'ha emès una factura amb número definitiu.
payment.receivedCobrament registrat
S'ha anotat un cobrament d'una factura.
client.createdClient creat
S'ha donat d'alta un client.
client.updatedClient actualitzat
S'han modificat les dades d'un client.
communication.inboundMissatge entrant
Ha arribat un email, SMS, WhatsApp o trucada d'un client.
email.sentEmail enviat
S'ha enviat un email (campanyes, avisos o API).
email.failedEmail fallit
Un email no s'ha pogut enviar.
email.openedEmail obert
El destinatari ha obert l'email.
email.clickedClic a l'email
El destinatari ha clicat un enllaç de l'email.
email.unsubscribedBaixa d'email
El destinatari s'ha donat de baixa dels emails.
email.bouncedEmail rebotat
L'email ha rebotat.
sms.sentSMS enviat
S'ha enviat un SMS.
sms.failedSMS fallit
Un SMS no s'ha pogut enviar.
sms.unsubscribedBaixa d'SMS
El destinatari ha demanat no rebre SMS.
whatsapp.unsubscribedBaixa de WhatsApp
El destinatari ha demanat no rebre WhatsApp.
campaign.finishedCampanya acabada
Una campanya ha acabat d'enviar-se.
3 mesos per 1 € →